import React, { useState, useEffect, useMemo } from 'react';
import { History, RotateCcw, ChevronDown, ChevronRight, User, Calendar, Tag, Search, X, Edit2, Maximize2, Check, Loader2, CloudUpload } from 'lucide-react';
import { getHistory, deleteHistoryEntry, HistoryEntry } from '../lib/supabase';
import { ExcelRow } from '../types';
import { useColumns } from '../contexts/ColumnsContext';
import { cn } from '../lib/utils';
import { usePersistentState } from '../contexts/FilterContext';
import { previewBusinessCentralSync, applyBusinessCentralSync, isPreviewTokenMismatchError } from '../services/businessCentral';
import { SyncStatusPill } from './SyncStatusPill';

interface HistoryViewProps {
  headers: string[];
  data: ExcelRow[];
  onRevert: (articleNo: string, oldData: ExcelRow, historyId?: string) => void;
  onEdit?: (rowIndex: number) => void;
}

type HistorySyncStatus = 'bc_pending' | 'previewed' | 'preview_only' | 'syncing' | 'synced' | 'failed';

interface HistorySyncRecord {
  selected: boolean;
  status: HistorySyncStatus;
  previewToken?: string;
  error?: string;
  warning?: string;
}

type HistorySyncMap = Record<string, HistorySyncRecord>;

function readStoredHistorySyncMap(): HistorySyncMap {
  try {
    const raw = localStorage.getItem('history-bcSync');
    if (!raw) return {};
    const parsed = JSON.parse(raw) as unknown;
    if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) return {};
    return parsed as HistorySyncMap;
  } catch {
    return {};
  }
}

export function HistoryView({ headers, data, onRevert, onEdit }: HistoryViewProps) {
  const COLUMNS = useColumns();
  const [history, setHistory] = useState<HistoryEntry[]>([]);
  const [loading, setLoading] = useState(true);
  const [expandedId, setExpandedId] = useState<string | null>(null);
  const [search, setSearch] = usePersistentState('history-search', '');
  const [userFilter, setUserFilter] = usePersistentState('history-userFilter', '');
  const [statusFilter, setStatusFilter] = usePersistentState<'all' | 'bc_pending' | 'previewed' | 'preview_only' | 'synced' | 'failed'>('history-statusFilter', 'all');
  const [bcHistorySync, setBcHistorySync] = useState<HistorySyncMap>(() => readStoredHistorySyncMap());
  const [bcSyncBusy, setBcSyncBusy] = useState(false);
  const [isFullscreen, setIsFullscreen] = useState(false);

  useEffect(() => {
    loadHistory();
  }, []);

  useEffect(() => {
    if (data.length > 0) {
      loadHistory();
    }
  }, [data]);

  useEffect(() => {
    try {
      localStorage.setItem('history-bcSync', JSON.stringify(bcHistorySync));
    } catch {
      // Ignore storage quota or serialization errors.
    }
  }, [bcHistorySync]);

  const loadHistory = async () => {
    setLoading(true);
    const historyData = await getHistory();
    setHistory(historyData);
    setLoading(false);
  };

  useEffect(() => {
    if (history.length === 0) return;
    const validKeys = new Set(history.map(entry => String(entry.id || `${entry.product_id}-${entry.changed_at}`)));
    setBcHistorySync(prev => {
      let changed = false;
      const next: Record<string, HistorySyncRecord> = {};
      for (const [key, value] of Object.entries(prev)) {
        if (!validKeys.has(key)) {
          changed = true;
          continue;
        }
        next[key] = value as HistorySyncRecord;
      }
      return changed ? next : prev;
    });
  }, [history]);

  const handleRevert = (entry: HistoryEntry) => {
    if (window.confirm(`Are you sure you want to revert changes for ${entry.article_name}?`)) {
      const currentRow = data.find(r => String(r[0]) === entry.product_id);
      if (currentRow && JSON.stringify(currentRow) === JSON.stringify(entry.old_data)) {
        if (!window.confirm("Reverting will restore original data. No actual changes will be made. Continue?")) {
          return;
        }
      }
      onRevert(entry.product_id, entry.old_data, entry.id);
    }
  };

  const getChangedFields = (oldData: ExcelRow, newData: ExcelRow) => {
    const changes: { header: string; old: any; new: any; index: number }[] = [];
    const maxLen = Math.max(oldData.length, newData.length);
    
    for (let i = 0; i < maxLen; i++) {
      if (oldData[i] !== newData[i]) {
        changes.push({
          header: headers[i] || `Col ${i}`,
          old: oldData[i],
          new: newData[i],
          index: i
        });
      }
    }
    return changes;
  };

  const formatDate = (dateStr: string) => {
    const date = new Date(dateStr);
    return new Intl.DateTimeFormat('en-GB', {
      day: '2-digit',
      month: '2-digit',
      year: 'numeric',
      hour: '2-digit',
      minute: '2-digit',
      second: '2-digit'
    }).format(date);
  };

  const uniqueUsers = Array.from(new Set(history.map(e => e.changed_by))).sort();

  const getEntryKey = (entry: HistoryEntry) => String(entry.id || `${entry.product_id}-${entry.changed_at}`);

  const getEntryStatus = (entry: HistoryEntry): HistorySyncStatus => {
    return bcHistorySync[getEntryKey(entry)]?.status || 'bc_pending';
  };

  const getEntrySelected = (entry: HistoryEntry): boolean => {
    return bcHistorySync[getEntryKey(entry)]?.selected || false;
  };

  // history is asc (oldest first) so index+1 = chronological #
  // display newest first by reversing for render only
  const filteredHistory = [...history].reverse().filter(entry => {
    if (userFilter && entry.changed_by !== userFilter) return false;
    const status = getEntryStatus(entry);
    if (statusFilter !== 'all' && status !== statusFilter) return false;
    const terms = search.toLowerCase().split(/\s+/).filter(Boolean);
    if (terms.length === 0) return true;
    const searchableText = `${entry.article_name} ${entry.product_id} ${entry.changed_by}`.toLowerCase();
    return terms.every(term => searchableText.includes(term));
  });

  const selectedEntries = useMemo(
    () => history.filter(entry => getEntrySelected(entry)),
    [history, bcHistorySync]
  );

  const statusCounts = useMemo(() => {
    const counts = { bc_pending: 0, previewed: 0, preview_only: 0, synced: 0, failed: 0 };
    history.forEach(entry => {
      const status = getEntryStatus(entry);
      if (status in counts) counts[status as keyof typeof counts] += 1;
    });
    return counts;
  }, [history, bcHistorySync]);

  const updateEntry = (entry: HistoryEntry, patch: Partial<HistorySyncRecord>) => {
    const key = getEntryKey(entry);
    setBcHistorySync(prev => ({
      ...prev,
      [key]: {
        selected: prev[key]?.selected ?? false,
        status: prev[key]?.status ?? 'bc_pending',
        previewToken: prev[key]?.previewToken,
        error: prev[key]?.error,
        ...prev[key],
        ...patch,
      },
    }));
  };

  const selectAllVisible = (selected: boolean) => {
    setBcHistorySync(prev => {
      const next = { ...prev };
      filteredHistory.forEach(entry => {
        const key = getEntryKey(entry);
        next[key] = {
          selected,
          status: next[key]?.status ?? 'bc_pending',
          previewToken: next[key]?.previewToken,
          error: next[key]?.error,
          warning: next[key]?.warning,
        };
      });
      return next;
    });
  };

  const discardSelected = () => {
    if (selectedEntries.length === 0) return;
    if (!window.confirm(`Discard ${selectedEntries.length} pending sync(s)? They will be reset to "Pending BC" and will not be synced to Business Central.`)) return;
    setBcHistorySync(prev => {
      const next = { ...prev };
      selectedEntries.forEach(entry => {
        const key = getEntryKey(entry);
        next[key] = { selected: false, status: 'bc_pending' };
      });
      return next;
    });
  };

  const previewSelected = async () => {
    if (selectedEntries.length === 0) return;
    setBcSyncBusy(true);
    try {
      for (const entry of [...selectedEntries].sort((a, b) => {
        const timeDelta = new Date(a.changed_at).getTime() - new Date(b.changed_at).getTime();
        if (timeDelta !== 0) return timeDelta;
        return String(a.id || '').localeCompare(String(b.id || ''));
      })) {
        const preview = await previewBusinessCentralSync(headers, entry.new_data);
        if (!preview.success) {
          updateEntry(entry, { status: 'failed', error: preview.error || 'Preview failed', warning: undefined, selected: true });
          continue;
        }
        updateEntry(entry, {
          status: 'previewed',
          previewToken: preview.previewToken,
          error: undefined,
          warning: undefined,
          selected: true,
        });
      }
    } finally {
      setBcSyncBusy(false);
    }
  };

  const syncSelected = async () => {
    if (selectedEntries.length === 0) return;
    setBcSyncBusy(true);
    try {
      const orderedEntries = [...selectedEntries].sort((a, b) => {
        const timeDelta = new Date(a.changed_at).getTime() - new Date(b.changed_at).getTime();
        if (timeDelta !== 0) return timeDelta;
        return String(a.id || '').localeCompare(String(b.id || ''));
      });

      for (const entry of orderedEntries) {
        updateEntry(entry, { status: 'syncing', error: undefined, selected: true });
        const key = getEntryKey(entry);
        const currentRecord = bcHistorySync[key];
        let previewToken = currentRecord?.previewToken;

        if (!previewToken) {
          const preview = await previewBusinessCentralSync(headers, entry.new_data);
          if (!preview.success) {
            updateEntry(entry, { status: 'failed', error: preview.error || 'Preview failed', warning: undefined, selected: true });
            continue;
          }
          previewToken = preview.previewToken;
          updateEntry(entry, { status: 'previewed', previewToken, error: undefined, warning: undefined, selected: true });
        }

        const apply = await applyBusinessCentralSync(headers, entry.new_data, previewToken);
        if (!apply.success) {
          if (isPreviewTokenMismatchError(apply.error)) {
            const refreshedPreview = await previewBusinessCentralSync(headers, entry.new_data);
            if (refreshedPreview.success) {
              updateEntry(entry, {
                status: 'previewed',
                previewToken: refreshedPreview.previewToken,
                error: undefined,
                warning: undefined,
                selected: true,
              });
              const retryApply = await applyBusinessCentralSync(headers, entry.new_data, refreshedPreview.previewToken);
              if (retryApply.success) {
                updateEntry(entry, {
                  status: 'synced',
                  error: undefined,
                  warning: retryApply.warning,
                  selected: false,
                  previewToken: retryApply.previewToken || refreshedPreview.previewToken,
                });
                continue;
              }
              updateEntry(entry, { status: 'failed', error: retryApply.error || 'BC sync failed', warning: retryApply.warning, selected: true });
              continue;
            }
          }
          updateEntry(entry, { status: 'failed', error: apply.error || 'BC sync failed', warning: apply.warning, selected: true });
          continue;
        }

        updateEntry(entry, {
          status: 'synced',
          error: undefined,
          warning: apply.warning,
          selected: false,
          previewToken: apply.previewToken || previewToken,
        });
      }
    } finally {
      setBcSyncBusy(false);
    }
  };

  if (loading) {
    return (
      <div className="flex flex-col items-center justify-center h-full text-slate-400">
        <div className="animate-spin rounded-full h-12 w-12 border-b-2 border-blue-500 mb-4"></div>
        <p className="text-lg">Fetching history...</p>
      </div>
    );
  }

  return (
    <div className={isFullscreen ? "fixed inset-0 z-40 bg-[#041021] p-6 overflow-auto" : "space-y-6 animate-in fade-in slide-in-from-bottom-4 duration-500"}>
      {isFullscreen && (
        <button
          onClick={() => setIsFullscreen(false)}
          className="fixed top-4 right-4 z-50 p-2 bg-slate-800 hover:bg-slate-700 text-slate-200 rounded-md transition-colors border border-slate-700"
        >
          <X className="w-5 h-5" />
        </button>
      )}
      <div className="flex items-center justify-between">
        <div>
          <h1 className="text-2xl font-bold text-white flex items-center gap-3">
            <History className="w-8 h-8 text-blue-500" />
            Change History
          </h1>
          <p className="text-slate-400 mt-1">
            {history.length > 0 ? (
              <><span className="text-white font-semibold">{history.length}</span> total records{filteredHistory.length !== history.length && <> &mdash; showing <span className="text-white font-semibold">{filteredHistory.length}</span></>}</>
            ) : 'Review and revert any changes made to products.'}
          </p>
        </div>
        <div className="flex items-center gap-4">
          <div className="relative">
            <User className="absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-slate-500 pointer-events-none" />
            <select
              value={userFilter}
              onChange={e => setUserFilter(e.target.value)}
              className={cn(
                "pl-9 pr-8 py-2 bg-slate-800 border rounded-md text-sm focus:outline-none focus:border-blue-500 transition-colors w-52 appearance-none",
                userFilter ? "border-blue-500 text-white" : "border-slate-700 text-slate-400"
              )}
            >
              <option value="">All users</option>
              {uniqueUsers.map(u => (
                <option key={u} value={u}>{u}</option>
              ))}
            </select>
            {userFilter && (
              <button
                onClick={() => setUserFilter('')}
                className="absolute right-2 top-1/2 -translate-y-1/2 text-slate-400 hover:text-white"
              >
                <X className="w-3.5 h-3.5" />
              </button>
            )}
          </div>
          <div className="relative">
            <Tag className="absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-slate-500" />
            <input
              type="text"
              placeholder="Search history..."
              value={search}
              onChange={(e) => setSearch(e.target.value)}
              className="pl-10 pr-10 py-2 bg-slate-800 border border-slate-700 rounded-md text-sm text-slate-200 focus:outline-none focus:border-blue-500 transition-colors w-64"
            />
            {search && (
              <button
                onClick={() => setSearch('')}
                className="absolute right-3 top-1/2 -translate-y-1/2 text-slate-400 hover:text-white"
              >
                <X className="w-4 h-4" />
              </button>
            )}
          </div>
          <button 
            onClick={loadHistory}
            className="px-4 py-2 bg-slate-800 hover:bg-slate-700 text-slate-200 rounded-md transition-colors flex items-center gap-2 border border-slate-700"
          >
            <RotateCcw className="w-4 h-4" />
            Refresh
          </button>
          <button
            onClick={() => setIsFullscreen(!isFullscreen)}
            className="p-2 bg-slate-800 hover:bg-slate-700 text-slate-200 rounded-md transition-colors border border-slate-700"
            title={isFullscreen ? "Exit fullscreen" : "Enter fullscreen"}
          >
            <Maximize2 className="w-5 h-5" />
          </button>
        </div>
      </div>

      <div className="bg-slate-900/70 border border-slate-800 rounded-xl p-4 flex flex-wrap items-center gap-3">
        <div className="flex items-center gap-2 text-xs text-slate-400">
          <span className="font-semibold text-slate-200">{selectedEntries.length}</span> selected
          <span className="text-slate-600">·</span>
          <span>{statusCounts.bc_pending} pending</span>
          <span>{statusCounts.previewed} previewed</span>
          <span>{statusCounts.preview_only} preview only</span>
          <span>{statusCounts.synced} synced</span>
          <span>{statusCounts.failed} failed</span>
        </div>
        <div className="ml-auto flex items-center gap-2 flex-wrap">
          <select
            value={statusFilter}
            onChange={e => setStatusFilter(e.target.value as any)}
            className="bg-slate-800 border border-slate-700 rounded-md px-3 py-2 text-xs text-slate-200 focus:outline-none focus:border-blue-500"
          >
            <option value="all">All statuses</option>
            <option value="bc_pending">Pending BC</option>
            <option value="previewed">Previewed</option>
            <option value="preview_only">Preview only</option>
            <option value="synced">Synced BC</option>
            <option value="failed">Failed</option>
          </select>
          <button
            onClick={() => selectAllVisible(true)}
            className="px-3 py-2 rounded-md bg-slate-800 hover:bg-slate-700 text-slate-200 text-xs border border-slate-700"
          >
            Select all visible
          </button>
          <button
            onClick={() => selectAllVisible(false)}
            className="px-3 py-2 rounded-md bg-slate-800 hover:bg-slate-700 text-slate-200 text-xs border border-slate-700"
          >
            Clear selection
          </button>
          <button
            onClick={discardSelected}
            disabled={selectedEntries.length === 0}
            className={cn(
              "px-3 py-2 rounded-md text-xs border transition-colors",
              selectedEntries.length === 0
                ? "bg-slate-700 text-slate-500 border-slate-600 cursor-not-allowed"
                : "bg-slate-800 hover:bg-red-900/40 text-red-400 border-red-500/30 hover:border-red-500/60"
            )}
          >
            Discard selected
          </button>
          <button
            onClick={previewSelected}
            disabled={bcSyncBusy || selectedEntries.length === 0}
            className={cn(
              "inline-flex items-center gap-2 px-4 py-2 rounded-md text-xs font-semibold border transition-colors",
              bcSyncBusy || selectedEntries.length === 0
                ? "bg-slate-700 text-slate-400 border-slate-600 cursor-not-allowed"
                : "bg-indigo-600 hover:bg-indigo-500 text-white border-indigo-500/30"
            )}
          >
            {bcSyncBusy ? <Loader2 className="w-3.5 h-3.5 animate-spin" /> : <Search className="w-3.5 h-3.5" />}
            Preview selected
          </button>
          <button
            onClick={syncSelected}
            disabled={bcSyncBusy || selectedEntries.length === 0}
            className={cn(
              "inline-flex items-center gap-2 px-4 py-2 rounded-md text-xs font-semibold border transition-colors",
              bcSyncBusy || selectedEntries.length === 0
                ? "bg-slate-700 text-slate-400 border-slate-600 cursor-not-allowed"
                : "bg-emerald-600 hover:bg-emerald-500 text-white border-emerald-500/30"
            )}
          >
            {bcSyncBusy ? <Loader2 className="w-3.5 h-3.5 animate-spin" /> : <CloudUpload className="w-3.5 h-3.5" />}
            Sync selected to BC
          </button>
        </div>
      </div>

      <div className="bg-[#0a1628] border border-slate-800 rounded-xl overflow-hidden shadow-2xl">
        {filteredHistory.length === 0 ? (
          <div className="p-12 text-center">
            <History className="w-12 h-12 text-slate-700 mx-auto mb-4" />
            <p className="text-slate-500 text-lg">No history records found.</p>
            <p className="text-slate-600 text-sm mt-1">
              {search ? "Try adjusting your search filters." : "Changes are recorded when you 'Save All' pending modifications."}
            </p>
          </div>
        ) : (
          <div className="divide-y divide-slate-800">
            {filteredHistory.map((entry, filteredIdx) => {
              const isExpanded = expandedId === entry.id;
              const changes = getChangedFields(entry.old_data, entry.new_data);
              const globalNumber = history.indexOf(entry) + 1;
              const status = getEntryStatus(entry);
              const selected = getEntrySelected(entry);

              return (
                <div key={entry.id} className={cn(
                  "transition-colors",
                  isExpanded ? "bg-blue-600/5" : "hover:bg-slate-800/30"
                )}>
                  {/* Summary Row */}
                  <div
                    className="p-4 flex items-center gap-4 cursor-pointer"
                    onClick={() => setExpandedId(isExpanded ? null : entry.id)}
                  >
                    <input
                      type="checkbox"
                      checked={selected}
                      onClick={e => e.stopPropagation()}
                      onChange={() => updateEntry(entry, { selected: !selected })}
                      className="accent-blue-500"
                    />
                    {isExpanded ? <ChevronDown className="w-5 h-5 text-slate-500" /> : <ChevronRight className="w-5 h-5 text-slate-500" />}

                    <div className="w-8 text-right shrink-0">
                      <span className="text-xs font-mono text-slate-500">#{globalNumber}</span>
                    </div>

                    <div className="flex-1 grid grid-cols-4 gap-4 items-center">
                      <div className="flex items-center gap-3">
                        <div className="w-10 h-10 rounded-lg bg-blue-500/10 flex items-center justify-center text-blue-500 font-bold shrink-0">
                          {entry.product_id.slice(0, 2).toUpperCase()}
                        </div>
                        <div className="min-w-0">
                          <div className="font-semibold text-slate-200 truncate">{entry.article_name}</div>
                          <div className="text-xs text-slate-500 font-mono">ID: {entry.product_id}</div>
                        </div>
                      </div>

                      <div className="flex items-center gap-2 text-slate-400">
                        <User className="w-4 h-4" />
                        <span className="text-sm truncate">{entry.changed_by}</span>
                      </div>

                      <div className="flex items-center gap-2 text-slate-400">
                        <Calendar className="w-4 h-4" />
                        <span className="text-sm">{formatDate(entry.changed_at)}</span>
                      </div>

                      <div className="flex flex-col items-end gap-2 text-sm">
                        <div className="flex items-center justify-end gap-3 flex-wrap">
                          <SyncStatusPill status={status} />
                          <span className="px-2.5 py-1 rounded-full bg-blue-500/10 text-blue-400 font-medium">
                            {changes.length} {changes.length === 1 ? 'change' : 'changes'}
                          </span>
                          <button
                            onClick={(e) => {
                              e.stopPropagation();
                              if (onEdit) {
                                const idx = data.findIndex(r => String(r[COLUMNS.ARTICLE_NO]) === entry.product_id);
                                if (idx !== -1) onEdit(idx);
                              }
                            }}
                            className="flex items-center gap-1.5 px-3 py-1.5 rounded-md bg-blue-500/10 text-blue-400 hover:bg-blue-500/20 transition-colors border border-blue-500/20"
                          >
                            <Edit2 className="w-4 h-4" />
                            Edit
                          </button>
                          <button
                            onClick={(e) => {
                              e.stopPropagation();
                              handleRevert(entry);
                            }}
                            className="flex items-center gap-1.5 px-3 py-1.5 rounded-md bg-orange-500/10 text-orange-400 hover:bg-orange-500/20 transition-colors border border-orange-500/20"
                          >
                            <RotateCcw className="w-4 h-4" />
                            Revert
                          </button>
                        </div>
                        {status === 'failed' && bcHistorySync[getEntryKey(entry)]?.error && (
                          <div className="max-w-[40rem] rounded-md border border-red-500/20 bg-red-500/10 px-3 py-2 text-xs text-red-200">
                            <span className="font-semibold">BC error:</span> {bcHistorySync[getEntryKey(entry)].error}
                          </div>
                        )}
                      </div>
                    </div>
                  </div>

                  {/* Details View */}
                  {isExpanded && (
                    <div className="px-14 pb-6 pt-2 animate-in slide-in-from-top-2 duration-300">
                      <div className="bg-[#040d1a] border border-slate-700/50 rounded-lg overflow-hidden">
                        <table className="w-full text-sm">
                          <thead>
                            <tr className="bg-slate-800/50 text-slate-400 text-left">
                              <th className="px-4 py-2 font-medium w-8">#</th>
                              <th className="px-4 py-2 font-medium">Column</th>
                              <th className="px-4 py-2 font-medium">Original Value</th>
                              <th className="px-4 py-2 font-medium">New Value</th>
                            </tr>
                          </thead>
                          <tbody className="divide-y divide-slate-800">
                            {changes.map((change, idx) => (
                              <tr key={idx} className="hover:bg-slate-700/20">
                                <td className="px-4 py-2 text-slate-600 text-xs font-mono">{idx + 1}</td>
                                <td className="px-4 py-2 text-slate-300 font-medium whitespace-nowrap">
                                  {change.header}
                                </td>
                                <td className="px-4 py-2">
                                  <span className="text-red-400/80 line-through decoration-red-500/50">
                                    {String(change.old ?? '-')}
                                  </span>
                                </td>
                                <td className="px-4 py-2">
                                  <span className="text-emerald-400 font-medium">
                                    {String(change.new ?? '-')}
                                  </span>
                                </td>
                              </tr>
                            ))}
                          </tbody>
                        </table>
                      </div>
                      <div className="mt-4 flex items-center justify-between px-2">
                        <div className="text-xs text-slate-500 flex items-center gap-1">
                          <Tag className="w-3 h-3" />
                          Row Index Reference: {entry.product_id}
                        </div>
                        <p className="text-xs text-slate-500 italic">
                          Reverting will move this record to 'Pending Validation' for final approval before re-syncing.
                        </p>
                      </div>
                    </div>
                  )}
                </div>
              );
            })}
          </div>
        )}
      </div>
    </div>
  );
}
