import React, { useEffect, useMemo, useState } from 'react';
import { useQueryClient } from '@tanstack/react-query';
import { openPath } from '@tauri-apps/plugin-opener';
import { AlertTriangle, Calculator, Check, Download, Play, RefreshCcw, Save, Table2 } from 'lucide-react';
import { researchApi } from '../../../research/researchApi';
import {
  researchQueryKeys,
  useResearchModelsQuery,
} from '../../../research/researchQueries';
import type {
  FinancialModel,
  ModelEvidenceStatus,
  ModelWorkbook,
  EvaluateFinancialModelResult,
  ResearchNote,
  ResearchWorkspace,
} from '../../../types/research';
import { UniverModelGrid } from './UniverModelGrid';

interface ModelWorkbenchProps {
  workspace: ResearchWorkspace;
  notes: ResearchNote[];
}

const evidenceClasses: Record<ModelEvidenceStatus, string> = {
  unsourced: 'border-term-border',
  single_source: 'border-yellow-400/80',
  corroborated: 'border-positive/80',
  inferred: 'border-orange-400/80',
  contradicted: 'border-negative/80',
  stale: 'border-term-text-muted/80',
};

const evidenceLabels: Record<ModelEvidenceStatus, string> = {
  unsourced: 'Unsourced',
  single_source: 'Single source',
  corroborated: 'Corroborated',
  inferred: 'Inferred',
  contradicted: 'Contradicted',
  stale: 'Stale',
};

const cloneWorkbook = (workbook: ModelWorkbook): ModelWorkbook =>
  JSON.parse(JSON.stringify(workbook)) as ModelWorkbook;

const currentThreeStatementPeriodHeaders = () => {
  const latestHistoricalYear = new Date().getFullYear() - 1;
  return Array.from({ length: 8 }, (_, index) => `FY ${latestHistoricalYear - 2 + index}`);
};

const normalizeThreeStatementPeriodHeaders = (model: FinancialModel): FinancialModel => {
  if (model.workbookJson.metadata?.mosaiciq?.template !== 'three_statement') {
    return model;
  }

  const periodHeaders = currentThreeStatementPeriodHeaders();
  const periodAddresses = ['B3', 'C3', 'D3', 'E3', 'F3', 'G3', 'H3', 'I3'];

  return {
    ...model,
    workbookJson: {
      ...model.workbookJson,
      sheets: model.workbookJson.sheets.map((sheet) => {
        const cells = { ...sheet.cells };
        periodAddresses.forEach((address, index) => {
          cells[address] = {
            ...(cells[address] ?? {}),
            value: periodHeaders[index],
          };
        });
        return {
          ...sheet,
          cells,
        };
      }),
    },
  };
};

const modelSignature = (model: FinancialModel | null) =>
  model
    ? JSON.stringify({
        workbookJson: model.workbookJson,
        annotations: model.annotations,
      })
    : '';

const formatTimestamp = (value: string | undefined) =>
  value
    ? new Intl.DateTimeFormat(undefined, {
        month: 'short',
        day: 'numeric',
        hour: 'numeric',
        minute: '2-digit',
      }).format(new Date(value))
    : 'Never saved';

export const ModelWorkbench: React.FC<ModelWorkbenchProps> = ({ workspace, notes }) => {
  const queryClient = useQueryClient();
  const modelsQuery = useResearchModelsQuery(workspace.id);
  const [selectedModelId, setSelectedModelId] = useState<string | null>(null);
  const [draft, setDraft] = useState<FinancialModel | null>(null);
  const [activeSheetId, setActiveSheetId] = useState<string | null>(null);
  const [isSaving, setIsSaving] = useState(false);
  const [isCreating, setIsCreating] = useState(false);
  const [isRefreshing, setIsRefreshing] = useState(false);
  const [isEvaluating, setIsEvaluating] = useState(false);
  const [isExporting, setIsExporting] = useState(false);
  const [evaluation, setEvaluation] = useState<EvaluateFinancialModelResult | null>(null);
  const [error, setError] = useState<string | null>(null);
  const [savedSignature, setSavedSignature] = useState('');

  const models = modelsQuery.data ?? [];

  useEffect(() => {
    if (!selectedModelId && models.length > 0) {
      setSelectedModelId(models[0].id);
    }
  }, [models, selectedModelId]);

  useEffect(() => {
    const selected = models.find((model) => model.id === selectedModelId) ?? null;
    const cloned = selected
      ? normalizeThreeStatementPeriodHeaders(
          JSON.parse(JSON.stringify(selected)) as FinancialModel,
        )
      : null;
    setDraft(cloned);
    setSavedSignature(modelSignature(cloned));
    setActiveSheetId(
      cloned?.workbookJson.activeSheetId ?? cloned?.workbookJson.sheets[0]?.id ?? null,
    );
  }, [models, selectedModelId]);

  const isDirty = useMemo(
    () => modelSignature(draft) !== savedSignature,
    [draft, savedSignature],
  );

  useEffect(() => {
    if (!isDirty) {
      return undefined;
    }
    const handleBeforeUnload = (event: BeforeUnloadEvent) => {
      event.preventDefault();
      event.returnValue = '';
    };
    window.addEventListener('beforeunload', handleBeforeUnload);
    return () => window.removeEventListener('beforeunload', handleBeforeUnload);
  }, [isDirty]);

  const selectModel = (modelId: string) => {
    if (
      isDirty &&
      !window.confirm('You have unsaved model edits. Switch models and discard them?')
    ) {
      return;
    }
    setSelectedModelId(modelId);
  };

  const createThreeStatementModel = async () => {
    setIsCreating(true);
    setError(null);
    try {
      const model = await researchApi.createFinancialModel({
        workspaceId: workspace.id,
        name: `${workspace.primaryTicker} 3-Statement Model`,
        ticker: workspace.primaryTicker,
        templateType: 'three_statement',
      });
      queryClient.setQueryData<FinancialModel[]>(
        researchQueryKeys.models(workspace.id),
        (current = []) => [model, ...current.filter((item) => item.id !== model.id)],
      );
      setSelectedModelId(model.id);
    } catch (caught) {
      setError(caught instanceof Error ? caught.message : String(caught));
    } finally {
      setIsCreating(false);
    }
  };

  const updateWorkbookDraft = (workbook: ModelWorkbook) => {
    if (!draft) {
      return;
    }
    setDraft({
      ...draft,
      workbookJson: {
        ...workbook,
        activeSheetId: activeSheetId ?? workbook.activeSheetId,
      },
    });
  };

  const saveModel = async () => {
    if (!draft) {
      return;
    }
    setIsSaving(true);
    setError(null);
    try {
      const workbookJson = cloneWorkbook({
        ...draft.workbookJson,
        activeSheetId: activeSheetId ?? draft.workbookJson.activeSheetId,
      });
      const saved = await researchApi.saveFinancialModel({
        modelId: draft.id,
        workbookJson,
        annotations: draft.annotations,
      });
      queryClient.setQueryData<FinancialModel[]>(
        researchQueryKeys.models(workspace.id),
        (current = []) =>
          current.map((model) => (model.id === saved.id ? saved : model)),
      );
      setDraft(saved);
      setSavedSignature(modelSignature(saved));
      setActiveSheetId(saved.workbookJson.activeSheetId ?? activeSheetId);
    } catch (caught) {
      setError(caught instanceof Error ? caught.message : String(caught));
    } finally {
      setIsSaving(false);
    }
  };

  const refreshBindings = async () => {
    if (!draft) {
      return;
    }
    setIsRefreshing(true);
    setError(null);
    try {
      await researchApi.refreshModelDataBindings({ modelId: draft.id });
      const refreshed = normalizeThreeStatementPeriodHeaders(
        await researchApi.getFinancialModel({ modelId: draft.id }),
      );
      queryClient.setQueryData<FinancialModel[]>(
        researchQueryKeys.models(workspace.id),
        (current = []) =>
          current.map((model) => (model.id === refreshed.id ? refreshed : model)),
      );
      setDraft(refreshed);
      setSavedSignature(modelSignature(refreshed));
      setActiveSheetId(refreshed.workbookJson.activeSheetId ?? activeSheetId);
    } catch (caught) {
      setError(caught instanceof Error ? caught.message : String(caught));
    } finally {
      setIsRefreshing(false);
    }
  };

  const evaluateModel = async () => {
    if (!draft) {
      return;
    }
    setIsEvaluating(true);
    setError(null);
    try {
      setEvaluation(
        await researchApi.evaluateFinancialModel({
          workbookJson: draft.workbookJson,
        }),
      );
    } catch (caught) {
      setError(caught instanceof Error ? caught.message : String(caught));
    } finally {
      setIsEvaluating(false);
    }
  };

  const exportModel = async () => {
    if (!draft || isDirty) {
      return;
    }
    setIsExporting(true);
    setError(null);
    try {
      const result = await researchApi.exportFinancialModelXlsx({ modelId: draft.id });
      await openPath(result.filePath);
    } catch (caught) {
      setError(caught instanceof Error ? caught.message : String(caught));
    } finally {
      setIsExporting(false);
    }
  };

  if (modelsQuery.isLoading) {
    return (
      <div className="rounded-[8px] border border-term-border bg-term-surface p-6 text-sm text-term-text-muted">
        Loading models...
      </div>
    );
  }

  if (models.length === 0) {
    return (
      <div className="flex min-h-[520px] items-center justify-center rounded-[8px] border border-dashed border-term-border bg-term-surface p-8">
        <div className="max-w-md text-center">
          <Calculator className="mx-auto h-8 w-8 text-term-text-muted" />
          <h2 className="mt-4 text-lg font-semibold text-term-text">No financial models</h2>
          <p className="mt-2 text-sm leading-6 text-term-text-muted">
            Create a standardized three-statement workbook with revenue build,
            statement links, evidence metadata, and historical data bindings.
          </p>
          <button
            type="button"
            className="mt-5 inline-flex items-center gap-2 rounded-[6px] border border-term-border bg-term-panel px-4 py-2 text-sm font-medium text-term-text hover:border-term-accent"
            onClick={createThreeStatementModel}
            disabled={isCreating}
          >
            <Table2 className="h-4 w-4" />
            {isCreating ? 'Creating...' : 'Create 3-Statement Model'}
          </button>
          {error ? <p className="mt-3 text-sm text-negative">{error}</p> : null}
        </div>
      </div>
    );
  }

  return (
    <section className="flex min-h-[620px] flex-col overflow-hidden rounded-[8px] border border-term-border bg-term-surface">
      <div className="flex flex-wrap items-center justify-between gap-3 border-b border-term-border px-4 py-3">
        <div className="flex items-center gap-2">
          <select
            className="rounded-[6px] border border-term-border bg-term-panel px-3 py-2 text-sm text-term-text"
            value={selectedModelId ?? ''}
            onChange={(event) => selectModel(event.target.value)}
          >
            {models.map((model) => (
              <option key={model.id} value={model.id}>
                {model.name}
              </option>
            ))}
          </select>
          <button
            type="button"
            className="inline-flex items-center gap-2 rounded-[6px] border border-term-border bg-term-panel px-3 py-2 text-sm text-term-text hover:border-term-accent"
            onClick={createThreeStatementModel}
            disabled={isCreating}
          >
            <Table2 className="h-4 w-4" />
            3 Statement
          </button>
        </div>
        <div className="flex items-center gap-2">
          {isDirty ? (
            <span className="inline-flex items-center gap-1 text-xs text-yellow-300">
              <AlertTriangle className="h-3.5 w-3.5" />
              Unsaved
            </span>
          ) : (
            <span className="inline-flex items-center gap-1 text-xs text-positive">
              <Check className="h-3.5 w-3.5" />
              Saved
            </span>
          )}
          <span className="text-xs text-term-text-muted">
            Updated {formatTimestamp(draft?.updatedAt)}
          </span>
          <span className="text-xs text-term-text-muted">
            {notes.length} workspace notes available for evidence links
          </span>
          <button
            type="button"
            className="inline-flex items-center gap-2 rounded-[6px] border border-term-border bg-term-panel px-3 py-2 text-sm font-medium text-term-text hover:border-term-accent"
            onClick={saveModel}
            disabled={!draft || isSaving || !isDirty}
          >
            <Save className="h-4 w-4" />
            {isSaving ? 'Saving...' : 'Save'}
          </button>
          <button
            type="button"
            className="inline-flex items-center gap-2 rounded-[6px] border border-term-border bg-term-panel px-3 py-2 text-sm font-medium text-term-text hover:border-term-accent"
            onClick={refreshBindings}
            disabled={!draft || isRefreshing || isDirty}
            title={isDirty ? 'Save before refreshing bound data' : undefined}
          >
            <RefreshCcw className="h-4 w-4" />
            {isRefreshing ? 'Refreshing...' : 'Refresh'}
          </button>
          <button
            type="button"
            className="inline-flex items-center gap-2 rounded-[6px] border border-term-border bg-term-panel px-3 py-2 text-sm font-medium text-term-text hover:border-term-accent"
            onClick={evaluateModel}
            disabled={!draft || isEvaluating}
          >
            <Play className="h-4 w-4" />
            {isEvaluating ? 'Evaluating...' : 'Evaluate'}
          </button>
          <button
            type="button"
            className="inline-flex items-center gap-2 rounded-[6px] border border-term-border bg-term-panel px-3 py-2 text-sm font-medium text-term-text hover:border-term-accent"
            onClick={exportModel}
            disabled={!draft || isExporting || isDirty}
            title={isDirty ? 'Save before exporting' : undefined}
          >
            <Download className="h-4 w-4" />
            {isExporting ? 'Opening...' : 'Open in Numbers'}
          </button>
        </div>
      </div>

      {error ? (
        <div className="border-b border-negative/30 bg-negative/10 px-4 py-2 text-sm text-negative">
          {error}
        </div>
      ) : null}

      <div className="flex gap-2 border-b border-term-border px-4 py-2">
        {draft?.workbookJson.sheets.map((sheet) => (
          <button
            key={sheet.id}
            type="button"
            className={`rounded-[6px] px-3 py-1.5 text-sm ${
              sheet.id === activeSheetId
                ? 'bg-term-accent text-term-bg'
                : 'bg-term-panel text-term-text-muted hover:text-term-text'
            }`}
            onClick={() => setActiveSheetId(sheet.id)}
          >
            {sheet.name}
          </button>
        ))}
      </div>

      <div className="flex min-h-0 flex-1">
        <div className="min-w-0 flex-1">
          {draft ? (
            <UniverModelGrid
              model={draft}
              activeSheetId={activeSheetId}
              onActiveSheetChange={setActiveSheetId}
              onWorkbookChange={updateWorkbookDraft}
            />
          ) : null}
        </div>
        <aside className="w-72 border-l border-term-border bg-term-panel p-4">
          <h3 className="text-sm font-semibold text-term-text">Evidence</h3>
          <p className="mt-2 text-sm leading-6 text-term-text-muted">
            Select a model cell to review linked notes, confidence, and evidence status.
          </p>
          {evaluation ? (
            <div className="mt-4 rounded-[6px] border border-term-border bg-term-bg p-3 text-xs text-term-text-muted">
              <div className="font-medium text-term-text">Evaluation</div>
              <div className="mt-1">{evaluation.evaluatedCells.length} cells calculated</div>
              <div>{evaluation.formulaErrors.length} formula errors</div>
              <div>{evaluation.dependencyGraph.length} dependencies</div>
            </div>
          ) : null}
          <div className="mt-4 space-y-2">
            {draft?.annotations.slice(0, 6).map((annotation) => (
              <div
                key={`${annotation.sheetId}:${annotation.address}`}
                className={`rounded-[6px] border bg-term-bg px-3 py-2 text-xs ${evidenceClasses[annotation.evidenceStatus]}`}
                title={evidenceLabels[annotation.evidenceStatus]}
              >
                <div className="font-medium text-term-text">
                  {annotation.sheetId} {annotation.address}
                </div>
                <div className="mt-1 text-term-text-muted">
                  {evidenceLabels[annotation.evidenceStatus]} · {annotation.linkedNoteIds.length} notes
                </div>
              </div>
            ))}
          </div>
        </aside>
      </div>
    </section>
  );
};
