import React, { useState, useMemo, useEffect } from 'react';
import * as XLSX from 'xlsx';
import { AppState, ExcelRow, COLUMNS } from './types';
import { Sidebar } from './components/Sidebar';
import { TopBar } from './components/TopBar';
import { ProductDescriptions } from './components/ProductDescriptions';
import { MatrixView } from './components/MatrixView';
import { EditPanel } from './components/EditPanel';
import { getAllSyncedRows, saveRowToSupabase, resetAllPendingRows, saveHistoryEntry, deleteHistoryEntry } from './lib/supabase';
import { getStoredSession, signOut, type AuthSession } from './lib/auth';
import { LoginPage } from './components/LoginPage';
import { DimensionsView } from './components/DimensionsView';
import { PricingView } from './components/PricingView';
import { ArticleDetails } from './components/ArticleDetails';
import { HistoryView } from './components/HistoryView';
import { UndoToast } from './components/UndoToast';
import { PendingValidationView } from './components/PendingValidationView';

export default function App() {
  const [session, setSession] = useState<AuthSession | null>(() => getStoredSession());

  const [appState, setAppState] = useState<AppState>({
    headers: [],
    data: [],
    fileName: '',
    fileDate: null,
    hasUnsavedChanges: false,
    asinColumnIndex: null
  });
  const [activeModule, setActiveModule] = useState<'descriptions' | 'article_details' | 'matrix' | 'dimensions' | 'pricing' | 'pending_validation' | 'history'>('descriptions');
  const [undoHistory, setUndoHistory] = useState<{ data: ExcelRow[], message: string }[]>([]);
  const [editingRowIndex, setEditingRowIndex] = useState<number | null>(null);
  const [isLoadingDefault, setIsLoadingDefault] = useState(true);
  const [defaultLoadError, setDefaultLoadError] = useState<string | null>(null);
  const [rowStatuses, setRowStatuses] = useState<Record<string, string>>({});
  const [pendingRows, setPendingRows] = useState<Record<string, { rowIndex: number; originalData: ExcelRow; newData: ExcelRow; articleName: string }>>({});
  const [isSavingAll, setIsSavingAll] = useState(false);

  useEffect(() => {
    console.log('[App] session changed:', session ? 'logged in' : 'logged out');
  }, [session]);

  const handleSignOut = () => {
    signOut();
    setSession(null);
  };

  useEffect(() => {
    const loadDefaultData = async () => {
      // In dev: Vite proxy handles /dropbox-file (see vite.config.ts)
      // In prod: Vercel serverless function at /api/dropbox-proxy handles it
      const fileUrl = import.meta.env.DEV
        ? '/dropbox-file/scl/fi/nkyabkq2jdwfudof2ovrl/Data-Matrix.xlsx?rlkey=1cz5fuabwipqqivihii7sybw0&st=io0g4wvb&dl=1'
        : '/api/dropbox-proxy';

      setIsLoadingDefault(true);
      setDefaultLoadError(null);

      try {
        console.log('Fetching Data-Matrix.xlsx via Vite proxy...');
        const response = await fetch(fileUrl);

        if (!response.ok) {
          throw new Error(`HTTP ${response.status}: ${response.statusText}`);
        }

        const arrayBuffer = await response.arrayBuffer();
        if (arrayBuffer.byteLength < 100) {
          throw new Error('File too small — possibly empty or error response');
        }

        const wb = XLSX.read(arrayBuffer, { type: 'array' });
        const wsname = wb.SheetNames[0];
        const ws = wb.Sheets[wsname];
        const data = XLSX.utils.sheet_to_json<any[]>(ws, { header: 1 });

        if (data.length > 0) {
          const rawHeaders = data[0];
          const rawRows = data.slice(1);

          // Find ASIN column index from headers (case insensitive)
          const asinIdx = (rawHeaders as string[]).findIndex((h: string) => 
            String(h).toLowerCase().trim() === 'asin'
          );
          if (asinIdx !== -1) {
            console.log('ASIN column found at index:', asinIdx);
          }

          console.log('Applying Supabase overrides...');
          const syncedData = await getAllSyncedRows();
          const articleNoIdx = COLUMNS.ARTICLE_NO;

          const processedRows = rawRows.map(row => {
            const articleNo = String(row[articleNoIdx]);
            const synced = syncedData[articleNo];
            const finalRow = synced ? synced.data : row;

            // Sync status_check
            if (synced && synced.status === 'pending') {
              setRowStatuses(prev => ({ ...prev, [articleNo]: 'pending' }));
            }

            // Format numeric/price fields to 2 decimal places
            return finalRow.map((val, idx) => {
              if (val === undefined || val === null || val === '') return val;
              const header = (rawHeaders[idx] || '').toLowerCase();

              // Skip Article No, Barcodes, and other code-like fields
              // But allow if it's a weight/measure column (e.g. Article NW (kg))
              if ((header.includes('id') || header.includes('no') || header.includes('code') ||
                header.includes('art.') || header.includes('barcode') || header.includes('article')) &&
                !(header.includes('nw') || header.includes('gw') || header.includes('weight') || header.includes('kg'))) {
                return val;
              }

              const formatKeywords = ['price', 'eur', 'cost', 'msrp', 'net', 'gross', 'netto', 'brutto', 'pp', 'pph', 'uvp', 'vpe', 'stk', 'nw', 'gw', 'weight', 'kg'];
              const shouldFormat = formatKeywords.some(kw => header.includes(kw));

              if (typeof val === 'number') {
                return Number(val.toFixed(2));
              }

              if (typeof val === 'string') {
                const normalized = val.trim().replace(',', '.');
                const num = parseFloat(normalized);
                if (!isNaN(num) && (shouldFormat || val.includes('.') || val.includes(','))) {
                  return num.toFixed(2);
                }
              }
              return val;
            });
          });

          setAppState({
            headers: rawHeaders,
            data: processedRows,
            fileName: 'Data-Matrix.xlsx (Cloud Sync)',
            fileDate: new Date(),
            hasUnsavedChanges: false,
            asinColumnIndex: asinIdx !== -1 ? asinIdx : null
          });
          setActiveModule('descriptions');
        }
      } catch (err) {
        console.error('Failed to load from Dropbox:', err);
        setDefaultLoadError(err instanceof Error ? err.message : 'Connection failed');
      } finally {
        setIsLoadingDefault(false);
      }
    };

    if (session) loadDefaultData();
  }, [session]);

  const handleFileUpload = (e: React.ChangeEvent<HTMLInputElement>) => {
    const file = e.target.files?.[0];
    if (!file) return;

    if (appState.hasUnsavedChanges) {
      if (!window.confirm('You have unsaved changes. Are you sure you want to load a new file and discard them?')) {
        e.target.value = '';
        return;
      }
    }

    const reader = new FileReader();
    reader.onload = (evt) => {
      const bstr = evt.target?.result;
      const wb = XLSX.read(bstr, { type: 'binary' });
      const wsname = wb.SheetNames[0];
      const ws = wb.Sheets[wsname];
      const data = XLSX.utils.sheet_to_json<any[]>(ws, { header: 1 });

      if (data.length > 0) {
        const rawHeaders = data[0];
        const rawRows = data.slice(1);

        const processedRows = rawRows.map(row => {
          return row.map((val, idx) => {
            if (val === undefined || val === null || val === '') return val;
            const header = (rawHeaders[idx] || '').toLowerCase();

            if (header.includes('id') || header.includes('no') || header.includes('code') ||
              header.includes('art.') || header.includes('barcode') || header.includes('article')) {
              // But allow if it's a weight/measure column (e.g. Article NW (kg))
              if (!(header.includes('nw') || header.includes('gw') || header.includes('weight') || header.includes('kg'))) {
                return val;
              }
            }

            // Handle date columns - Excel serial dates are numbers >= 25569 (Jan 1, 1970)
            if (header.includes('date') || header.includes('launch') || header.includes('ready')) {
              if (typeof val === 'number' && val >= 25569 && val <= 60000) {
                const excelEpoch = new Date(1899, 11, 30);
                const date = new Date(excelEpoch.getTime() + val * 86400000);
                return date.toLocaleDateString('en-GB', { day: '2-digit', month: '2-digit', year: 'numeric' });
              }
              return val;
            }

            const formatKeywords = ['price', 'eur', 'cost', 'msrp', 'net', 'gross', 'netto', 'brutto', 'pp', 'pph', 'uvp', 'vpe', 'stk', 'nw', 'gw', 'weight', 'kg'];
            const shouldFormat = formatKeywords.some(kw => header.includes(kw));

            if (typeof val === 'number') {
              return Number(val.toFixed(2));
            }

            if (typeof val === 'string') {
              const normalized = val.trim().replace(',', '.');
              const num = parseFloat(normalized);
              if (!isNaN(num) && (shouldFormat || val.includes('.') || val.includes(','))) {
                return num.toFixed(2);
              }
            }
            return val;
          });
        });

        setAppState({
          headers: rawHeaders,
          data: processedRows,
          fileName: file.name,
          fileDate: new Date(),
          hasUnsavedChanges: false,
          asinColumnIndex: null
        });
        setActiveModule('descriptions');
      }
    };
    reader.readAsBinaryString(file);
  };

  const handleExport = () => {
    if (appState.data.length === 0) return;

    const wsData = [appState.headers, ...appState.data];
    const ws = XLSX.utils.aoa_to_sheet(wsData);
    const wb = XLSX.utils.book_new();
    XLSX.utils.book_append_sheet(wb, ws, 'Products');

    const dateStr = new Date().toISOString().split('T')[0];
    XLSX.writeFile(wb, `CRAZE_Products_Updated_${dateStr}.xlsx`);

    // 3. Post-export: Reset pending statuses in Supabase
    console.log('Resetting pending statuses in Supabase...');
    resetAllPendingRows().then(success => {
      if (success) {
        console.log('Successfully reset all pending statuses');
        setRowStatuses({}); // Clear local statuses
      }
    });

    setAppState(prev => ({ ...prev, hasUnsavedChanges: false }));
  };

  const handleSaveRow = (rowIndex: number, updatedRow: ExcelRow) => {
    const articleNo = String(updatedRow[COLUMNS.ARTICLE_NO]);
    const originalData = appState.data[rowIndex]; // Capture before update
    setAppState(prev => {
      const newData = [...prev.data];
      newData[rowIndex] = updatedRow;
      return { ...prev, data: newData, hasUnsavedChanges: true };
    });
    setPendingRows(prev => ({
      ...prev,
      [articleNo]: {
        rowIndex,
        // Keep the very first originalData if already pending (re-edit case)
        originalData: prev[articleNo]?.originalData ?? originalData,
        newData: updatedRow,
        articleName: String(updatedRow[COLUMNS.ARTICLE_NAME] || articleNo),
      }
    }));
    setRowStatuses(prev => ({ ...prev, [articleNo]: 'pending' }));
    setEditingRowIndex(null);
  };

  const handleRevertRow = (articleNo: string) => {
    const pending = pendingRows[articleNo];
    if (!pending) return;
    setAppState(prev => {
      const newData = [...prev.data];
      newData[pending.rowIndex] = pending.originalData;
      const stillPending = Object.keys(pendingRows).length > 1;
      return { ...prev, data: newData, hasUnsavedChanges: stillPending };
    });
    setPendingRows(prev => { const n = { ...prev }; delete n[articleNo]; return n; });
    setRowStatuses(prev => { const n = { ...prev }; delete n[articleNo]; return n; });
  };

  const handleSaveAll = async () => {
    const entries = Object.entries(pendingRows) as [string, { rowIndex: number; originalData: ExcelRow; newData: ExcelRow; articleName: string }][];
    if (entries.length === 0) return;
    setIsSavingAll(true);
    let allSuccess = true;
    for (const [articleNo, { newData, originalData, articleName }] of entries) {
      const success = await saveRowToSupabase(articleNo, newData);
      if (success) {
        // Also save to history
        await saveHistoryEntry(articleNo, articleName, originalData, newData, session?.user?.email || 'unknown');
        
        setRowStatuses(prev => ({ ...prev, [articleNo]: 'saved' }));
        setPendingRows(prev => { const n = { ...prev }; delete n[articleNo]; return n; });
      } else {
        setRowStatuses(prev => ({ ...prev, [articleNo]: 'error' }));
        allSuccess = false;
      }
    }
    if (allSuccess) setAppState(prev => ({ ...prev, hasUnsavedChanges: false }));
    setIsSavingAll(false);
  };

  const captureState = (message: string) => {
    setUndoHistory(prev => {
      const newState = {
        data: JSON.parse(JSON.stringify(appState.data)), // Deep copy
        message
      };
      // Keep last 50 steps
      const newHistory = [newState, ...prev].slice(0, 50);
      return newHistory;
    });
  };

  const handleUndo = () => {
    if (undoHistory.length === 0) return;

    const [lastAction, ...remainingHistory] = undoHistory;
    setAppState(prev => ({
      ...prev,
      data: lastAction.data,
      hasUnsavedChanges: true
    }));
    setUndoHistory(remainingHistory);
  };

  const stats = useMemo(() => {
    if (appState.data.length === 0) return null;
    let missingDeLong = 0;
    let missingEnLong = 0;
    let missingDeShort = 0;
    let missingEnShort = 0;
    let fullyComplete = 0;

    appState.data.forEach(row => {
      const deLong = row[COLUMNS.LONG_DE];
      const enLong = row[COLUMNS.LONG_EN];
      const deShort = row[COLUMNS.SHORT_DE];
      const enShort = row[COLUMNS.SHORT_EN];

      if (!deLong) missingDeLong++;
      if (!enLong) missingEnLong++;
      if (!deShort) missingDeShort++;
      if (!enShort) missingEnShort++;

      if (deLong && enLong && deShort && enShort) fullyComplete++;
    });

    return {
      total: appState.data.length,
      missingDeLong,
      missingEnLong,
      missingDeShort,
      missingEnShort,
      fullyComplete
    };
  }, [appState.data]);

  if (!session) {
    return <LoginPage onLogin={() => {
      const stored = getStoredSession();
      console.log('[App] onLogin, stored session:', stored ? 'found' : 'null');
      setSession(stored);
    }} />;
  }

  return (
    <div className="h-screen bg-[#040d1a] text-slate-200 flex flex-col font-sans overflow-hidden">
      <TopBar
        stats={stats}
        onExport={handleExport}
        hasData={appState.data.length > 0}
        hasUnsavedChanges={appState.hasUnsavedChanges}
        userEmail={session.user.email}
        onSignOut={handleSignOut}
        canUndo={undoHistory.length > 0}
        onUndo={handleUndo}
        undoMessage={undoHistory[0]?.message}
        undoSteps={undoHistory.length}
        pendingCount={Object.keys(pendingRows).length}
        pendingChanges={Object.fromEntries(Object.entries(pendingRows).map(([k, v]) => [k, { articleName: (v as any).articleName }]))}
        onSaveAll={handleSaveAll}
        onRevertRow={handleRevertRow}
        isSavingAll={isSavingAll}
      />
      <div className="flex flex-1 overflow-hidden">
        <Sidebar activeModule={activeModule} setActiveModule={setActiveModule} />
        <main className="flex-1 overflow-auto relative p-6 bg-[#041021]">
          {isLoadingDefault ? (
            <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">Loading latest data...</p>
            </div>
          ) : defaultLoadError && appState.data.length === 0 ? (
            <div className="flex flex-col items-center justify-center h-full text-red-400">
              <p className="mb-4 text-lg">Failed to auto-load data: {defaultLoadError}</p>
              <label className="cursor-pointer bg-blue-600 hover:bg-blue-700 text-white px-6 py-3 rounded-lg shadow-lg transition-colors">
                Load Excel File Manually
                <input type="file" accept=".xlsx, .xls" className="hidden" onChange={handleFileUpload} />
              </label>
            </div>
          ) : appState.data.length === 0 && activeModule !== 'upload' ? (
            <div className="flex flex-col items-center justify-center h-full text-slate-400">
              <p className="mb-4 text-lg">No data loaded.</p>
              <label className="cursor-pointer bg-blue-600 hover:bg-blue-700 text-white px-6 py-3 rounded-lg shadow-lg transition-colors">
                Load Excel File
                <input type="file" accept=".xlsx, .xls" className="hidden" onChange={handleFileUpload} />
              </label>
            </div>
          ) : (
            <>
              {activeModule === 'descriptions' && (
                <ProductDescriptions
                  data={appState.data}
                  headers={appState.headers}
                  asinColumnIndex={appState.asinColumnIndex}
                  onEdit={(index) => setEditingRowIndex(index)}
                  rowStatuses={rowStatuses}
                />
              )}
              {activeModule === 'matrix' && (
                <MatrixView data={appState.data} headers={appState.headers} rowStatuses={rowStatuses} />
              )}

              {activeModule === 'dimensions' && (
                <DimensionsView
                  data={appState.data}
                  headers={appState.headers}
                  onEdit={(index) => setEditingRowIndex(index)}
                  onSaveRow={handleSaveRow}
                  onCaptureState={captureState}
                  rowStatuses={rowStatuses}
                  onRevertRow={handleRevertRow}
                />
              )}

              {activeModule === 'pricing' && (
                <PricingView
                  data={appState.data}
                  headers={appState.headers}
                  onSaveRow={handleSaveRow}
                  onCaptureState={captureState}
                  onEdit={(index) => setEditingRowIndex(index)}
                  rowStatuses={rowStatuses}
                />
              )}
              {activeModule === 'article_details' && (
                <ArticleDetails
                  data={appState.data}
                  onEdit={(index) => setEditingRowIndex(index)}
                  rowStatuses={rowStatuses}
                />
              )}
              {activeModule === 'pending_validation' && (
                <PendingValidationView
                  data={appState.data}
                  pendingRows={pendingRows}
                  rowStatuses={rowStatuses}
                  onRevertRow={handleRevertRow}
                  onEdit={(index) => setEditingRowIndex(index)}
                />
              )}
              {activeModule === 'history' && (
                <HistoryView 
                  headers={appState.headers}
                  data={appState.data}
                  onRevert={async (articleNo, revertedData, historyId) => {
                    // Find the row in appState.data and update it
                    const rowIndex = appState.data.findIndex(r => String(r[COLUMNS.ARTICLE_NO]) === articleNo);
                    if (rowIndex !== -1) {
                      setAppState(prev => {
                        const newData = [...prev.data];
                        newData[rowIndex] = revertedData;
                        return { ...prev, data: newData, hasUnsavedChanges: true };
                      });
                      // Mark as pending for sync
                      setRowStatuses(prev => ({ ...prev, [articleNo]: 'pending' }));
                      setPendingRows(prev => ({
                        ...prev,
                        [articleNo]: {
                          rowIndex,
                          originalData: appState.data[rowIndex],
                          newData: revertedData,
                          articleName: String(revertedData[COLUMNS.ARTICLE_NAME] || articleNo),
                        }
                      }));
                      // Delete the history entry after revert
                      if (historyId) {
                        await deleteHistoryEntry(String(historyId));
                      }
                    }
                  }}
                />
              )}
            </>
          )}
        </main>
      </div>

      <UndoToast
        undoState={undoHistory[0] || null}
        onUndo={handleUndo}
        onClose={() => {
          // Instead of clearing history, we can just hide the toast
          // But since UndoToast is driven by undoHistory[0], 
          // we might want a way to "acknowledge" the current top of history
          // For now, let's just not clear the history.
        }}
      />

      {editingRowIndex !== null && (
        <EditPanel
          row={appState.data[editingRowIndex]}
          rowIndex={editingRowIndex}
          onSave={handleSaveRow}
          onClose={() => setEditingRowIndex(null)}
          onCaptureState={captureState}
        />
      )}
    </div>
  );
}
