'use client';

import { useState } from 'react';
import { Table } from '@tanstack/react-table';
import SearchableSelect from '@/components/SearchableSelect';

export interface ToolbarFilterOption {
  label: string;
  value: string;
}

export interface ToolbarFilterConfig {
  columnId: string;
  title: string;
  placeholder?: string;
  options: ToolbarFilterOption[];
}

// Opt-in export configuration. CSV/Excel are generated client-side from the
// table's currently filtered rows unless a custom handler is supplied. PDF has
// no client-side generator (the app ships no PDF lib), so the PDF button only
// appears when `onExportPdf` is provided (e.g. wired to a backend export).
export interface ExportConfig {
  fileName: string;
  onExportCsv?: () => void;
  onExportExcel?: () => void;
  onExportPdf?: () => void;
  exporting?: string | null;
}

interface DataTableToolbarProps<TData> {
  table: Table<TData>;
  searchPlaceholder?: string;
  filters?: ToolbarFilterConfig[];
  renderAdditionalActions?: () => React.ReactNode;
  collapsibleFilters?: boolean;
  enableColumnVisibility?: boolean;
  exportConfig?: ExportConfig;
}

// Exported so filter bars outside the DataTable (e.g. the Recruiter dashboard)
// render identical controls instead of re-declaring the classes. Purely style
// constants — no behaviour lives here.
export const BTN =
  'flex items-center gap-2 px-3.5 py-2.5 rounded-none text-xs font-bold bg-white dark:bg-slate-900 border border-slate-200 dark:border-slate-800 text-slate-700 dark:text-slate-300 hover:border-indigo-500/60 hover:text-indigo-600 dark:hover:text-indigo-400 transition disabled:opacity-50 disabled:cursor-not-allowed cursor-pointer';

export const CLEAR_FILTERS_BTN =
  'bg-rose-50 hover:bg-rose-100 text-rose-600 dark:bg-rose-950/30 dark:hover:bg-rose-900/50 dark:text-rose-450 border border-rose-200/50 dark:border-rose-900/30 rounded-none px-4 py-2.5 text-xs font-bold transition flex items-center gap-1.5 cursor-pointer';

/** Collapsible filter panel shell — the grey tray the filter controls sit in. */
export const FILTER_PANEL =
  'bg-slate-50 dark:bg-slate-950/40 border border-slate-200 dark:border-slate-800 rounded-none p-4';

/** Count badge on the "Filters" toggle. */
export const FILTER_COUNT_BADGE =
  'inline-flex items-center justify-center min-w-[18px] h-[18px] px-1 rounded-full bg-indigo-600 text-white text-[10px] font-black';

/** Just the caption text of a filter label. */
export const FILTER_LABEL_TEXT =
  'text-[10px] font-bold uppercase tracking-wider text-slate-400 dark:text-slate-500';

/** Stacked label + control, as used by the date-range filters. Only put this on
 *  a wrapper whose control sets its own casing/weight (e.g. a date input) —
 *  `uppercase`/`tracking-wider` cascade, so selects need FILTER_LABEL_TEXT. */
export const FILTER_LABEL = `flex flex-col ${FILTER_LABEL_TEXT}`;

/** Date/text input inside a filter panel. */
export const FILTER_INPUT =
  'mt-1 text-xs px-2 py-1.5 border border-slate-200 dark:border-slate-800 bg-white dark:bg-slate-950 text-slate-800 dark:text-white focus:outline-none focus:border-indigo-500';

function csvCell(v: unknown): string {
  const s = v === null || v === undefined ? '' : String(v);
  return /[",\n\r]/.test(s) ? `"${s.replace(/"/g, '""')}"` : s;
}

/** Pull header labels + raw values for every visible, data-bearing column. */
function exportMatrix<TData>(table: Table<TData>): { headers: string[]; rows: string[][] } {
  const cols = table.getVisibleLeafColumns().filter((c) => {
    const def = c.columnDef as { accessorKey?: unknown; accessorFn?: unknown };
    return def.accessorKey !== undefined || def.accessorFn !== undefined;
  });
  const headers = cols.map((c) =>
    typeof c.columnDef.header === 'string' ? c.columnDef.header : c.id,
  );
  const rows = table.getFilteredRowModel().rows.map((r) =>
    cols.map((c) => {
      let v: unknown;
      try {
        v = r.getValue(c.id);
      } catch {
        v = '';
      }
      if (v === null || v === undefined) return '';
      if (typeof v === 'object') return JSON.stringify(v);
      return String(v);
    }),
  );
  return { headers, rows };
}

function download(blob: Blob, filename: string) {
  const url = URL.createObjectURL(blob);
  const a = document.createElement('a');
  a.href = url;
  a.download = filename;
  a.click();
  URL.revokeObjectURL(url);
}

export function DataTableToolbar<TData>({
  table,
  searchPlaceholder = 'Search...',
  filters = [],
  renderAdditionalActions,
  collapsibleFilters = false,
  enableColumnVisibility = false,
  exportConfig,
}: DataTableToolbarProps<TData>) {
  const globalFilter = (table.getState().globalFilter as string) ?? '';
  const activeColumnFilters = table.getState().columnFilters.length;
  const isFiltered = globalFilter !== '' || activeColumnFilters > 0;

  const [filtersOpen, setFiltersOpen] = useState(false);
  const [columnsOpen, setColumnsOpen] = useState(false);

  const defaultCsv = () => {
    const { headers, rows } = exportMatrix(table);
    const csv = [headers, ...rows].map((r) => r.map(csvCell).join(',')).join('\r\n');
    download(new Blob(['﻿' + csv], { type: 'text/csv;charset=utf-8;' }), `${exportConfig!.fileName}.csv`);
  };
  const defaultExcel = async () => {
    const { headers, rows } = exportMatrix(table);
    const XLSX = await import('xlsx');
    const ws = XLSX.utils.aoa_to_sheet([headers, ...rows]);
    const wb = XLSX.utils.book_new();
    XLSX.utils.book_append_sheet(wb, ws, 'Sheet1');
    XLSX.writeFile(wb, `${exportConfig!.fileName}.xlsx`);
  };

  const hideableColumns = table.getAllLeafColumns().filter((c) => c.getCanHide());

  const filterControls = filters.map((filter) => {
    const column = table.getColumn(filter.columnId);
    if (!column) return null;
    const columnValue = (column.getFilterValue() as string) ?? '';
    return (
      <SearchableSelect
        key={filter.columnId}
        value={columnValue || 'ALL'}
        onChange={(val) => column.setFilterValue(val === 'ALL' || val === '' ? undefined : val)}
        className="w-44"
        isClearable={false}
        options={[
          { value: 'ALL', label: filter.placeholder || `All ${filter.title}` },
          ...filter.options.map((o) => ({ value: o.value, label: o.label })),
        ]}
      />
    );
  });

  return (
    <div className="space-y-3">
      <div className="flex flex-col md:flex-row gap-3 items-center justify-between">
        {/* Search Input */}
        <div className="relative w-full md:max-w-[260px]">
          <i className="fa-solid fa-magnifying-glass absolute left-3.5 top-3 text-slate-400 dark:text-slate-500 w-4 h-4"></i>
          <input
            type="text"
            placeholder={searchPlaceholder}
            value={globalFilter}
            onChange={(e) => table.setGlobalFilter(e.target.value)}
            className="w-full bg-slate-50 dark:bg-slate-950 border border-slate-200 dark:border-slate-800 hover:border-slate-300 dark:hover:border-slate-700 focus:border-indigo-500 dark:focus:border-indigo-500 rounded-none pl-10 pr-4 py-2.5 text-xs focus:outline-none transition-all duration-300 focus:ring-2 focus:ring-indigo-500/20 text-slate-800 dark:text-white font-semibold"
          />
        </div>

        {/* Actions row */}
        <div className="flex flex-wrap gap-3 w-full md:w-auto items-center justify-start md:justify-end">
          {/* Inline filters (when not collapsible) */}
          {!collapsibleFilters && filterControls}

          {/* Collapsible filters toggle */}
          {collapsibleFilters && filters.length > 0 && (
            <button
              type="button"
              onClick={() => setFiltersOpen((o) => !o)}
              className={BTN}
            >
              <i className="fa-solid fa-sliders"></i>
              Filters
              {activeColumnFilters > 0 && (
                <span className={FILTER_COUNT_BADGE}>{activeColumnFilters}</span>
              )}
              <i className={`fa-solid fa-chevron-${filtersOpen ? 'up' : 'down'} text-[10px]`}></i>
            </button>
          )}

          {/* Column show/hide */}
          {enableColumnVisibility && hideableColumns.length > 0 && (
            <div className="relative">
              <button type="button" onClick={() => setColumnsOpen((o) => !o)} className={BTN}>
                <i className="fa-solid fa-table-columns"></i>
                Columns
                <i className={`fa-solid fa-chevron-${columnsOpen ? 'up' : 'down'} text-[10px]`}></i>
              </button>
              {columnsOpen && (
                <>
                  <div className="fixed inset-0 z-20" onClick={() => setColumnsOpen(false)} />
                  <div className="absolute right-0 mt-1 z-30 w-52 max-h-72 overflow-y-auto bg-white dark:bg-slate-900 border border-slate-200 dark:border-slate-800 rounded-none shadow-xl p-2">
                    {hideableColumns.map((column) => {
                      const label =
                        typeof column.columnDef.header === 'string' ? column.columnDef.header : column.id;
                      return (
                        <label
                          key={column.id}
                          className="flex items-center gap-2 px-2 py-1.5 text-xs font-semibold text-slate-700 dark:text-slate-300 hover:bg-slate-50 dark:hover:bg-slate-800/60 cursor-pointer"
                        >
                          <input
                            type="checkbox"
                            checked={column.getIsVisible()}
                            onChange={(e) => column.toggleVisibility(e.target.checked)}
                            className="accent-indigo-600"
                          />
                          <span className="truncate">{label}</span>
                        </label>
                      );
                    })}
                  </div>
                </>
              )}
            </div>
          )}

          {/* Export */}
          {exportConfig && (
            <>
              <button
                type="button"
                onClick={exportConfig.onExportCsv ?? defaultCsv}
                disabled={exportConfig.exporting != null}
                className={BTN}
                title="Export as CSV"
              >
                <i className={`text-sm ${exportConfig.exporting === 'csv' ? 'fa-solid fa-spinner fa-spin' : 'fa-solid fa-file-csv'}`}></i>
                CSV
              </button>
              <button
                type="button"
                onClick={exportConfig.onExportExcel ?? defaultExcel}
                disabled={exportConfig.exporting != null}
                className={BTN}
                title="Export as Excel"
              >
                <i className={`text-sm ${exportConfig.exporting === 'excel' ? 'fa-solid fa-spinner fa-spin' : 'fa-solid fa-file-excel'}`}></i>
                Excel
              </button>
              {exportConfig.onExportPdf && (
                <button
                  type="button"
                  onClick={exportConfig.onExportPdf}
                  disabled={exportConfig.exporting != null}
                  className={BTN}
                  title="Export as PDF"
                >
                  <i className={`text-sm ${exportConfig.exporting === 'pdf' ? 'fa-solid fa-spinner fa-spin' : 'fa-solid fa-file-pdf'}`}></i>
                  PDF
                </button>
              )}
            </>
          )}

          {isFiltered && (
            <button
              onClick={() => {
                table.resetGlobalFilter();
                table.resetColumnFilters();
              }}
              className={CLEAR_FILTERS_BTN}
            >
              <i className="fa-solid fa-xmark"></i> Clear Filters
            </button>
          )}

          {renderAdditionalActions && renderAdditionalActions()}
        </div>
      </div>

      {/* Collapsible filter panel */}
      {collapsibleFilters && filtersOpen && filters.length > 0 && (
        <div className={FILTER_PANEL}>
          <div className="flex flex-wrap gap-3 items-center">{filterControls}</div>
        </div>
      )}
    </div>
  );
}
