import { DataTable, DataTableSortStatus } from 'mantine-datatable';
import { useEffect, useState, useMemo } from 'react';
import sortBy from 'lodash/sortBy';
import IconPin from './Icon/IconPin';

type Column = {
  accessor: string;
  title?: any;
  sortable?: boolean;
  render?: (row: any) => React.ReactNode;
  width?: number | string;
};

type Props = {
  data: any[];
  columns: Column[];
  pageSizes?: number[];
  height?: number;
  enableCheckbox?: boolean;
  selectedRecords?: any[];
  onSelectedRecordsChange?: (records: any[]) => void;
  isLoading?: boolean;
  initialSortStatus?: DataTableSortStatus;
  idAccessor?: string;
  enablePin?: boolean;
  pinnedIds?: (string | number)[];
  onPinnedChange?: (pinnedIds: (string | number)[]) => void;
  pinStorageKey?: string;
};

const DynamicTable = ({
  data,
  columns,
  pageSizes = [10, 20, 30],
  height,
  enableCheckbox = false, 
  selectedRecords, 
  onSelectedRecordsChange,
  isLoading = false,
  initialSortStatus,
  idAccessor = 'id',
  enablePin = false,
  pinnedIds,
  onPinnedChange,
  pinStorageKey,
}: Props) => {
  const [page, setPage] = useState(1);
  const [pageSize, setPageSize] = useState(pageSizes[0]);
  const [internalSelectedRecords, setInternalSelectedRecords] = useState<any[]>([]);
  const [internalPinnedIds, setInternalPinnedIds] = useState<(string | number)[]>(() => {
    if (pinStorageKey) {
      try {
        const stored = localStorage.getItem(pinStorageKey);
        return stored ? JSON.parse(stored) : [];
      } catch {
        return [];
      }
    }
    return [];
  });

  const [sortStatus, setSortStatus] = useState<DataTableSortStatus>(
    initialSortStatus || {
      columnAccessor: 'date',
      direction: 'desc',
    }
  );

  const isControlled = selectedRecords !== undefined && onSelectedRecordsChange !== undefined;
  const selected = isControlled ? selectedRecords : internalSelectedRecords;

  const handleSelectionChange = (records: any[]) => {
    if (isControlled) {
      onSelectedRecordsChange?.(records);
    } else {
      setInternalSelectedRecords(records);
    }
  };

  const isPinControlled = pinnedIds !== undefined && onPinnedChange !== undefined;
  const currentPinnedIds = useMemo(() => {
    const raw = isPinControlled ? pinnedIds : internalPinnedIds;
    return (raw || []).map((id) => String(id));
  }, [isPinControlled, pinnedIds, internalPinnedIds]);

  const handleTogglePin = (id: string | number, e: React.MouseEvent) => {
    e.stopPropagation();
    const idStr = String(id);
    const isPinned = currentPinnedIds.includes(idStr);
    const next = isPinned
      ? currentPinnedIds.filter((p) => p !== idStr)
      : [idStr, ...currentPinnedIds];

    if (isPinControlled) {
      onPinnedChange?.(next);
    } else {
      setInternalPinnedIds(next);
      if (pinStorageKey) {
        try {
          localStorage.setItem(pinStorageKey, JSON.stringify(next));
        } catch (err) {
          console.error('Failed to save pinned IDs:', err);
        }
      }
    }
  };

  const currentPinnedSet = useMemo(() => new Set(currentPinnedIds), [currentPinnedIds]);

  const sanitizedData = useMemo(() => {
    return data.map((row: any, idx: number) => {
      if (row && (row[idAccessor] === undefined || row[idAccessor] === null || row[idAccessor] === '')) {
        return {
          ...row,
          [idAccessor]: row.customer || row.phone || row.order_no || row.orderNo || row.shipment_no || row.shipmentid || `row-${idx}`,
        };
      }
      return row;
    });
  }, [data, idAccessor]);

  const sortedRecords = useMemo(() => {
    const hasPins = enablePin && currentPinnedSet.size > 0;
    const isRowPinned = (row: any) => {
      if (!hasPins) return false;
      const rowId = String(row[idAccessor] ?? row.orderNo ?? row.order_no ?? row.shipmentid ?? '');
      return currentPinnedSet.has(rowId);
    };

    const sorted = [...sanitizedData].sort((a: any, b: any) => {
      // 1. PIN PRIORITY ALWAYS COMES FIRST!
      if (hasPins) {
        const pinnedA = isRowPinned(a);
        const pinnedB = isRowPinned(b);
        if (pinnedA && !pinnedB) return -1;
        if (!pinnedA && pinnedB) return 1;
        if (pinnedA && pinnedB) {
          const idA = String(a[idAccessor] ?? a.orderNo ?? a.order_no ?? a.shipmentid ?? '');
          const idB = String(b[idAccessor] ?? b.orderNo ?? b.order_no ?? b.shipmentid ?? '');
          const idxA = currentPinnedIds.indexOf(idA);
          const idxB = currentPinnedIds.indexOf(idB);
          if (idxA !== -1 && idxB !== -1) return idxA - idxB;
        }
      }

      // 2. Normal sorting
      if (!sortStatus.columnAccessor) return 0;

      const key = sortStatus.columnAccessor;
      let valA = a[key];
      let valB = b[key];

      if (key === 'date') {
        valA = a.rawTimestamp !== undefined ? a.rawTimestamp : new Date(a.date || a.created_at || 0).getTime();
        valB = b.rawTimestamp !== undefined ? b.rawTimestamp : new Date(b.date || b.created_at || 0).getTime();
      } else if (key === 'orderNo' || key === 'id' || key === 'shipmentid') {
        valA = a.rawId !== undefined ? a.rawId : (parseInt(String(a.orderNo || a.shipmentid || a.id).replace(/\D/g, ''), 10) || a[key]);
        valB = b.rawId !== undefined ? b.rawId : (parseInt(String(b.orderNo || b.shipmentid || b.id).replace(/\D/g, ''), 10) || b[key]);
      } else if (key === 'total' || key === 'amount') {
        valA = Number(a.total ?? a.amount) || 0;
        valB = Number(b.total ?? b.amount) || 0;
      }

      if (typeof valA === 'string' && typeof valB === 'string') {
        return sortStatus.direction === 'asc' ? valA.localeCompare(valB) : valB.localeCompare(valA);
      }

      if (valA < valB) return sortStatus.direction === 'asc' ? -1 : 1;
      if (valA > valB) return sortStatus.direction === 'asc' ? 1 : -1;
      return 0;
    });

    return sorted;
  }, [sanitizedData, sortStatus, enablePin, currentPinnedSet, currentPinnedIds, idAccessor]);

  const pageRecords = useMemo(() => {
    const from = (page - 1) * pageSize;
    const to = from + pageSize;
    return sortedRecords.slice(from, to);
  }, [page, pageSize, sortedRecords]);

  // Reset to first page when data changes or sort changes
  useEffect(() => {
    setPage(1);
  }, [data, sortStatus, pageSize]);

  const allColumns = useMemo(() => {
    if (!enablePin) return columns;

    let pinnedCount = 0;
    if (currentPinnedSet.size > 0) {
      for (let i = 0; i < sanitizedData.length; i++) {
        const r = sanitizedData[i];
        const rowId = String(r[idAccessor] ?? r.orderNo ?? r.order_no ?? r.shipmentid ?? '');
        if (currentPinnedSet.has(rowId)) pinnedCount++;
      }
    }

    const pinCol: Column = {
      accessor: '__pin',
      width: 44,
      title: (
        <div
          className="flex items-center justify-center cursor-default select-none"
          title={pinnedCount > 0 ? `${pinnedCount} item(s) pinned to top` : 'Pin item to top'}
        >
          <span className="relative flex items-center justify-center">
            <IconPin className={`w-3.5 h-3.5 ${pinnedCount > 0 ? 'text-amber-600' : 'text-gray-400'}`} fill={pinnedCount > 0} />
            {pinnedCount > 0 && (
              <span className="absolute -top-1.5 -right-2 bg-amber-500 text-white rounded-full text-[9px] font-bold px-1 min-w-[14px] h-[14px] flex items-center justify-center shadow-xs leading-none">
                {pinnedCount}
              </span>
            )}
          </span>
        </div>
      ),
      render: (row: any) => {
        const rowId = String(row[idAccessor] ?? row.orderNo ?? row.order_no ?? row.shipmentid ?? '');
        const isPinned = currentPinnedIds.includes(rowId);
        return (
          <div className="flex items-center justify-center">
            <button
              type="button"
              title={isPinned ? 'Unpin from top' : 'Pin to top'}
              aria-label={isPinned ? 'Unpin item' : 'Pin item to top'}
              className={`p-1 rounded-md transition-all duration-150 cursor-pointer flex items-center justify-center ${
                isPinned
                  ? 'text-amber-700 bg-amber-100 hover:bg-amber-200 ring-1 ring-amber-300 shadow-xs'
                  : 'text-gray-300 hover:text-amber-600 hover:bg-amber-50'
              }`}
              onClick={(e) => handleTogglePin(row[idAccessor] ?? row.orderNo ?? row.shipmentid, e)}
            >
              <IconPin className="w-3.5 h-3.5" fill={isPinned} />
            </button>
          </div>
        );
      },
    };

    return [pinCol, ...columns];
  }, [columns, enablePin, currentPinnedSet, sanitizedData, idAccessor]);

  const enhancedColumns = allColumns.map((col, index) => {
    const isFirst = index === 0 && !enableCheckbox;

    if (col.accessor === '__pin') {
      return {
        ...col,
        render: (row: any) => (col.render ? col.render(row) : null),
      };
    }

    return {
      ...col,

      render: (row: any) => (
        <div
          className={`${isFirst ? 'sticky left-0 z-9 px-3 py-1' : ''
            }`}
        >
          {col.render ? col.render(row) : row[col.accessor]}
        </div>
      ),

      title: (
        <div className={isFirst ? 'sticky left-0 z-10' : ''}>
          {col.title}
        </div>
      ),
    };
  });

  return (
    <div className="w-full overflow-x-auto border rounded-md">
      <div className="min-w-[900px]">
        <DataTable
          highlightOnHover
          className="whitespace-nowrap table-hover"
          height={height}
          idAccessor={idAccessor}
          records={pageRecords}
          fetching={isLoading}
          columns={enhancedColumns}
          sortStatus={sortStatus}
          onSortStatusChange={setSortStatus}
          totalRecords={data.length}
          page={page}
          onPageChange={setPage}
          recordsPerPage={pageSize}
          recordsPerPageOptions={pageSizes}
          onRecordsPerPageChange={setPageSize}
          minHeight={300}
          paginationText={({ from, to, totalRecords }) =>
            `Showing ${from} to ${to} of ${totalRecords} entries`
          }
          rowClassName={(record: any) => {
            if (!enablePin || currentPinnedIds.length === 0) return '';
            const rowId = String(record[idAccessor] ?? record.orderNo ?? record.order_no ?? record.shipmentid ?? '');
            return currentPinnedIds.includes(rowId) ? '!bg-amber-50/70 border-l-4 !border-l-amber-500' : '';
          }}
          {...(enableCheckbox
            ? {
                selectedRecords: selected || [],
                onSelectedRecordsChange: handleSelectionChange,
              } as any
            : {})}
          withBorder
        />
      </div>
    </div>
  );
};

export default DynamicTable;