import React, { useState, useEffect } from 'react';
import { useTranslation } from 'react-i18next';
import * as XLSX from 'xlsx';
import {
  FaFileExport, FaTimes, FaFileCsv, FaFileExcel, FaDownload,
  FaSearch, FaCheckSquare, FaSquare, FaSpinner,
} from 'react-icons/fa';
import { useDoctypeFields, type DoctypeField } from '../hooks/useDoctypeFields';

// ─────────────────────────────────────────────
// Types
// ─────────────────────────────────────────────

export type ExportFormat = 'csv' | 'excel';
export type ExportScope  = 'selected' | 'all_on_page' | 'all_with_filters';

export interface DynamicExportModalProps {
  /** Whether the modal is open */
  isOpen: boolean;
  onClose: () => void;

  /** Frappe DocType name, e.g. "Work_Order", "Asset" */
  doctype: string;

  /** Counts for the three scope options */
  selectedCount: number;
  pageCount: number;
  totalCount: number;

  /**
   * Called when the user clicks Export.
   * `rows` is the flat array of objects to export (already resolved by parent).
   * `columns` is the list of chosen column keys.
   * `format` is 'csv' | 'excel'.
   *
   * Alternatively you can pass `onFetchAll` and let the modal handle fetching.
   */
  onExport?: (scope: ExportScope, format: ExportFormat, columns: string[]) => Promise<void> | void;

  /**
   * If provided, the modal will call this to fetch ALL records when
   * scope === 'all_with_filters'. The parent just needs to provide page data.
   */
  onFetchAll?: () => Promise<any[]>;

  /** Current page data (used for 'all_on_page' and 'selected') */
  pageData: any[];

  /** Set of selected row names/ids */
  selectedRows?: Set<string>;
  rowKey?: string; // default: 'name'

  /** Optional: extra columns to inject (e.g. computed / virtual fields) */
  extraColumns?: DoctypeField[];

  /** Optional: columns to hide even if they exist in DocType */
  hiddenColumns?: string[];

  /** Optional: override default-checked columns (fieldnames) */
  defaultColumns?: string[];

  /** File name prefix, e.g. "work_orders" → "work_orders_2025-01-01.csv" */
  fileNamePrefix?: string;
}

// ─────────────────────────────────────────────
// Helpers
// ─────────────────────────────────────────────

function formatValue(value: any): string {
  if (value === null || value === undefined) return '';
  if (typeof value === 'boolean') return value ? 'Yes' : 'No';
  return String(value);
}

function downloadCSV(rows: any[], columns: DoctypeField[], fileName: string) {
  const headers = columns.map(c => c.label);
  const body = rows.map(row =>
    columns.map(c => {
      const val = formatValue(row[c.key]);
      // Escape CSV
      if (val.includes(',') || val.includes('"') || val.includes('\n')) {
        return `"${val.replace(/"/g, '""')}"`;
      }
      return val;
    }).join(',')
  );
  const csv = [headers.join(','), ...body].join('\n');
  const blob = new Blob(['\ufeff' + csv], { type: 'text/csv;charset=utf-8;' });
  const url = URL.createObjectURL(blob);
  const a = document.createElement('a');
  a.href = url;
  a.download = fileName;
  a.click();
  URL.revokeObjectURL(url);
}

function downloadExcel(rows: any[], columns: DoctypeField[], fileName: string) {
  const wsData = [
    columns.map(c => c.label),
    ...rows.map(row => columns.map(c => formatValue(row[c.key]))),
  ];
  const ws = XLSX.utils.aoa_to_sheet(wsData);
  const wb = XLSX.utils.book_new();
  XLSX.utils.book_append_sheet(wb, ws, 'Export');
  XLSX.writeFile(wb, fileName);
}

// ─────────────────────────────────────────────
// Component
// ─────────────────────────────────────────────

const DynamicExportModal: React.FC<DynamicExportModalProps> = ({
  isOpen,
  onClose,
  doctype,
  selectedCount,
  pageCount,
  totalCount,
  onExport,
  onFetchAll,
  pageData,
  selectedRows,
  rowKey = 'name',
  extraColumns = [],
  hiddenColumns = [],
  defaultColumns,
  fileNamePrefix,
}) => {
  const { t } = useTranslation();
  const { fields, loading: fieldsLoading } = useDoctypeFields(doctype);

  // ── Derived column list ──────────────────────────────────────
  const allColumns: DoctypeField[] = React.useMemo(() => {
    const hidden = new Set(hiddenColumns);

    // Merge fetched fields + extra columns, remove hidden
    const base = [
      ...fields.filter(f => !hidden.has(f.key)),
      ...extraColumns.filter(f => !hidden.has(f.key)),
    ];

    // Apply defaultColumns override if provided
    if (defaultColumns) {
      const defaultSet = new Set(defaultColumns);
      return base.map(f => ({ ...f, default: defaultSet.has(f.key) }));
    }

    return base;
  }, [fields, extraColumns, hiddenColumns, defaultColumns]);

  // ── Local state ───────────────────────────────────────────────
  const [scope, setScope]   = useState<ExportScope>(selectedCount > 0 ? 'selected' : 'all_with_filters');
  const [format, setFormat] = useState<ExportFormat>('csv');
  const [checkedKeys, setCheckedKeys] = useState<Set<string>>(new Set());
  const [search, setSearch] = useState('');
  const [isExporting, setIsExporting] = useState(false);

  // Track whether we have seeded checkedKeys for this modal open session
  const initializedRef = React.useRef(false);

  // Sync scope when selectedCount changes
  useEffect(() => {
    setScope(selectedCount > 0 ? 'selected' : 'all_with_filters');
  }, [selectedCount]);

  // Seed default checked columns ONCE when allColumns first populates.
  // Using a ref guard prevents re-seeding when allColumns recomputes due to
  // inline prop arrays (defaultColumns={[...]} creates a new reference every
  // parent render), which would silently wipe out the user's All/None/Default selection.
  useEffect(() => {
    if (allColumns.length === 0) return;
    if (initializedRef.current) return;
    initializedRef.current = true;
    setCheckedKeys(new Set(allColumns.filter(c => c.default).map(c => c.key)));
  }, [allColumns]);

  // Reset the seed flag when modal closes so next open re-initializes cleanly
  useEffect(() => {
    if (!isOpen) {
      initializedRef.current = false;
      setCheckedKeys(new Set());
    }
  }, [isOpen]);

  if (!isOpen) return null;

  // ── Column helpers ────────────────────────────────────────────
  const filteredColumns = search.trim()
    ? allColumns.filter(c =>
        c.label.toLowerCase().includes(search.toLowerCase()) ||
        c.key.toLowerCase().includes(search.toLowerCase())
      )
    : allColumns;

  const toggleColumn = (key: string) => {
    setCheckedKeys(prev => {
      const next = new Set(prev);
      next.has(key) ? next.delete(key) : next.add(key);
      return next;
    });
  };

  const selectAll = () => setCheckedKeys(new Set(allColumns.map(c => c.key)));
  const selectDefault = () => setCheckedKeys(new Set(allColumns.filter(c => c.default).map(c => c.key)));
  const selectNone = () => setCheckedKeys(new Set());

  // ── Export handler ────────────────────────────────────────────
  const handleExport = async () => {
    if (checkedKeys.size === 0) return;
    setIsExporting(true);

    try {
      // If parent handles everything
      if (onExport) {
        await onExport(scope, format, [...checkedKeys]);
        onClose();
        return;
      }

      // Otherwise handle internally
      let rows: any[] = [];
      if (scope === 'selected') {
        const sel = selectedRows ?? new Set<string>();
        rows = pageData.filter(r => sel.has(r[rowKey]));
      } else if (scope === 'all_on_page') {
        rows = pageData;
      } else {
        if (!onFetchAll) {
          alert('onFetchAll not provided for all_with_filters scope');
          return;
        }
        rows = await onFetchAll();
      }

      if (rows.length === 0) {
        alert('No data to export.');
        return;
      }

      const chosenCols = allColumns.filter(c => checkedKeys.has(c.key));
      const prefix  = fileNamePrefix ?? doctype.toLowerCase().replace(/\s+/g, '_');
      const datePart = new Date().toISOString().split('T')[0];
      const fileName  = `${prefix}_export_${datePart}.${format === 'csv' ? 'csv' : 'xlsx'}`;

      if (format === 'csv') {
        downloadCSV(rows, chosenCols, fileName);
      } else {
        downloadExcel(rows, chosenCols, fileName);
      }

      onClose();
    } catch (err) {
      console.error('Export failed:', err);
      alert(`Export failed: ${err instanceof Error ? err.message : 'Unknown error'}`);
    } finally {
      setIsExporting(false);
    }
  };

  // ── Render ────────────────────────────────────────────────────
  return (
    <div className="fixed inset-0 bg-black/50 flex items-center justify-center z-[70] p-4">
      <div className="bg-white dark:bg-gray-800 rounded-lg shadow-xl w-full max-w-2xl max-h-[92vh] flex flex-col animate-scale-in">

        {/* ── Header ── */}
        <div className="bg-gradient-to-r from-green-500 to-green-600 px-6 py-4 rounded-t-lg flex-shrink-0">
          <div className="flex items-center justify-between">
            <div className="flex items-center gap-3">
              <FaFileExport className="text-white text-xl" />
              <div>
                <h3 className="text-lg font-semibold text-white">Export {doctype.replace(/_/g, ' ')}</h3>
                <p className="text-green-100 text-xs mt-0.5">
                  {allColumns.length} fields available · {checkedKeys.size} selected
                </p>
              </div>
            </div>
            <button onClick={onClose} className="text-white/80 hover:text-white transition-colors" disabled={isExporting}>
              <FaTimes size={20} />
            </button>
          </div>
        </div>

        {/* ── Body (scrollable) ── */}
        <div className="flex-1 overflow-y-auto p-6 space-y-6">

          {/* Scope */}
          <div>
            <h4 className="text-sm font-semibold text-gray-700 dark:text-gray-300 mb-3">What to export</h4>
            <div className="space-y-2">
              {/* Selected rows */}
              <ScopeOption
                value="selected"
                current={scope}
                onChange={setScope}
                disabled={selectedCount === 0}
                badge={selectedCount}
                badgeColor="green"
                label="Selected rows"
                sub={`${selectedCount} row${selectedCount !== 1 ? 's' : ''} selected`}
              />
              {/* Current page */}
              <ScopeOption
                value="all_on_page"
                current={scope}
                onChange={setScope}
                badge={pageCount}
                badgeColor="blue"
                label="Current page"
                sub={`${pageCount} rows on this page`}
              />
              {/* All with filters */}
              <ScopeOption
                value="all_with_filters"
                current={scope}
                onChange={setScope}
                badge={totalCount}
                badgeColor="purple"
                label="All records (current filters)"
                sub={`${totalCount} total matching records`}
              />
            </div>
          </div>

          {/* Format */}
          <div>
            <h4 className="text-sm font-semibold text-gray-700 dark:text-gray-300 mb-3">File format</h4>
            <div className="flex gap-3">
              <FormatOption value="csv"   current={format} onChange={setFormat}
                icon={<FaFileCsv className="text-green-600 text-xl" />}
                label="CSV" sub="Universal, works everywhere" />
              <FormatOption value="excel" current={format} onChange={setFormat}
                icon={<FaFileExcel className="text-green-700 text-xl" />}
                label="Excel (.xlsx)" sub="Native Excel workbook" />
            </div>
          </div>

          {/* Column picker */}
          <div>
            <div className="flex items-center justify-between mb-2">
              <h4 className="text-sm font-semibold text-gray-700 dark:text-gray-300">
                Columns to export
                {fieldsLoading && <FaSpinner className="inline ml-2 animate-spin text-gray-400" size={12} />}
              </h4>
              <div className="flex gap-3 text-xs text-blue-600 dark:text-blue-400">
                <button onClick={selectAll}     className="hover:underline">All</button>
                <button onClick={selectDefault} className="hover:underline">Default</button>
                <button onClick={selectNone}    className="hover:underline">None</button>
              </div>
            </div>

            {/* Search */}
            <div className="relative mb-2">
              <FaSearch className="absolute left-2.5 top-1/2 -translate-y-1/2 text-gray-400" size={12} />
              <input
                type="text"
                value={search}
                onChange={e => setSearch(e.target.value)}
                placeholder="Search fields…"
                className="w-full pl-8 pr-3 py-1.5 text-xs border border-gray-300 dark:border-gray-600 rounded-md focus:outline-none focus:ring-2 focus:ring-green-500 bg-white dark:bg-gray-700 text-gray-900 dark:text-white"
              />
              {search && (
                <button onClick={() => setSearch('')} className="absolute right-2 top-1/2 -translate-y-1/2 text-gray-400 hover:text-gray-600">
                  <FaTimes size={10} />
                </button>
              )}
            </div>

            {/* Field grid */}
            {fieldsLoading ? (
              <div className="flex items-center justify-center h-24 text-gray-400 text-sm gap-2">
                <FaSpinner className="animate-spin" /> Loading fields…
              </div>
            ) : (
              <div className="grid grid-cols-2 md:grid-cols-3 gap-1.5 max-h-52 overflow-y-auto p-2 bg-gray-50 dark:bg-gray-900/50 rounded-lg border border-gray-200 dark:border-gray-700">
                {filteredColumns.map(col => {
                  const checked = checkedKeys.has(col.key);
                  return (
                    <div
                      key={col.key}
                      onClick={() => toggleColumn(col.key)}
                      className={`flex items-center gap-2 px-2 py-1.5 rounded cursor-pointer transition-all text-xs select-none ${
                        checked
                          ? 'bg-green-100 dark:bg-green-900/30 text-green-800 dark:text-green-200'
                          : 'hover:bg-gray-100 dark:hover:bg-gray-800 text-gray-600 dark:text-gray-400'
                      }`}
                    >
                      <span className="flex-shrink-0">
                        {checked
                          ? <FaCheckSquare size={13} className="text-green-600" />
                          : <FaSquare size={13} className="text-gray-300 dark:text-gray-600" />}
                      </span>
                      <span className="truncate" title={`${col.label} (${col.key})`}>
                        {col.label}
                      </span>
                    </div>
                  );
                })}
                {filteredColumns.length === 0 && (
                  <p className="col-span-3 text-center text-gray-400 text-xs py-4">
                    No fields match "{search}"
                  </p>
                )}
              </div>
            )}
            <p className="text-xs text-gray-400 mt-1.5">
              {checkedKeys.size} of {allColumns.length} fields selected
              {search && ` · showing ${filteredColumns.length} matching`}
            </p>
          </div>
        </div>

        {/* ── Footer ── */}
        <div className="flex-shrink-0 px-6 py-4 bg-gray-50 dark:bg-gray-900/50 border-t border-gray-200 dark:border-gray-700 rounded-b-lg flex justify-between items-center">
          <p className="text-xs text-gray-500 dark:text-gray-400">
            {scope === 'selected'        && `Exporting ${selectedCount} selected row${selectedCount !== 1 ? 's' : ''}`}
            {scope === 'all_on_page'     && `Exporting ${pageCount} rows from current page`}
            {scope === 'all_with_filters' && `Exporting up to ${totalCount} records`}
          </p>
          <div className="flex gap-3">
            <button
              onClick={onClose}
              disabled={isExporting}
              className="px-4 py-2 text-sm font-medium text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700 rounded-lg transition-colors"
            >
              Cancel
            </button>
            <button
              onClick={handleExport}
              disabled={checkedKeys.size === 0 || isExporting}
              className="px-4 py-2 text-sm font-medium text-white bg-green-600 hover:bg-green-700 rounded-lg transition-colors flex items-center gap-2 disabled:opacity-50 disabled:cursor-not-allowed"
            >
              {isExporting ? (
                <><FaSpinner className="animate-spin" size={14} /> Exporting…</>
              ) : (
                <><FaDownload size={14} /> Export</>
              )}
            </button>
          </div>
        </div>
      </div>
    </div>
  );
};

// ─────────────────────────────────────────────
// Sub-components
// ─────────────────────────────────────────────

const BADGE_COLORS: Record<string, string> = {
  green:  'bg-green-100  dark:bg-green-900/40  text-green-700  dark:text-green-300',
  blue:   'bg-blue-100   dark:bg-blue-900/40   text-blue-700   dark:text-blue-300',
  purple: 'bg-purple-100 dark:bg-purple-900/40 text-purple-700 dark:text-purple-300',
};

interface ScopeOptionProps {
  value: ExportScope;
  current: ExportScope;
  onChange: (v: ExportScope) => void;
  disabled?: boolean;
  label: string;
  sub: string;
  badge: number;
  badgeColor: 'green' | 'blue' | 'purple';
}

const ScopeOption: React.FC<ScopeOptionProps> = ({ value, current, onChange, disabled, label, sub, badge, badgeColor }) => (
  <label className={`flex items-center gap-3 p-3 rounded-lg border cursor-pointer transition-all ${
    current === value
      ? 'border-green-500 bg-green-50 dark:bg-green-900/20'
      : 'border-gray-200 dark:border-gray-700 hover:bg-gray-50 dark:hover:bg-gray-700/50'
  } ${disabled ? 'opacity-50 cursor-not-allowed' : ''}`}>
    <input
      type="radio" name="export_scope" value={value}
      checked={current === value}
      onChange={() => !disabled && onChange(value)}
      disabled={disabled}
      className="text-green-600 focus:ring-green-500"
    />
    <div className="flex-1 min-w-0">
      <div className="font-medium text-sm text-gray-900 dark:text-white">{label}</div>
      <div className="text-xs text-gray-500 dark:text-gray-400">{sub}</div>
    </div>
    <span className={`px-2 py-0.5 rounded text-xs font-semibold flex-shrink-0 ${BADGE_COLORS[badgeColor]}`}>
      {badge.toLocaleString()}
    </span>
  </label>
);

interface FormatOptionProps {
  value: ExportFormat;
  current: ExportFormat;
  onChange: (v: ExportFormat) => void;
  icon: React.ReactNode;
  label: string;
  sub: string;
}

const FormatOption: React.FC<FormatOptionProps> = ({ value, current, onChange, icon, label, sub }) => (
  <label className={`flex-1 flex items-center gap-3 p-3 rounded-lg border cursor-pointer transition-all ${
    current === value
      ? 'border-green-500 bg-green-50 dark:bg-green-900/20'
      : 'border-gray-200 dark:border-gray-700 hover:bg-gray-50 dark:hover:bg-gray-700/50'
  }`}>
    <input
      type="radio" name="export_format" value={value}
      checked={current === value}
      onChange={() => onChange(value)}
      className="text-green-600 focus:ring-green-500"
    />
    {icon}
    <div>
      <div className="font-medium text-sm text-gray-900 dark:text-white">{label}</div>
      <div className="text-xs text-gray-500 dark:text-gray-400">{sub}</div>
    </div>
  </label>
);

export default DynamicExportModal;