import React from 'react';
import { BalanceSheetPanelData } from '../../types/financial';
import {
  StatementTableMinimal,
  formatNumber,
} from '../ui/StatementTableMinimal';
import {
  type UnitOption,
  type UnitScale,
  UNIT_OPTIONS,
  computeAutoUnit,
  formatScaled,
  scaleWarningNumbers,
  unitLabel,
} from '../ui/UnitScale';
import { InlineMappingEditor } from '../Mappings/InlineMappingEditor';
import type { MappingCellInfo } from '../../hooks/useEarningsMappings';

interface BalanceSheetPanelProps {
  data: BalanceSheetPanelData;
  onRunCommand?: (command: string) => void;
}

export const buildBalanceSheetCommand = (
  symbol: string,
  frequency: BalanceSheetPanelData['frequency'],
  options: {
    start?: string;
    end?: string;
    currency?: string;
  } = {},
) => {
  const parts = ['/bs', symbol, frequency];
  if (options.start && options.end) {
    parts.push(options.start, options.end);
  }
  if (options.currency) {
    parts.push('--currency', options.currency.toUpperCase());
  }
  return parts.join(' ');
};

const SourceAttribution: React.FC<{
  status: BalanceSheetPanelData['sourceStatus'];
}> = ({ status }) => {
  return (
    <div className="text-[11px] font-mono text-term-text-muted">
      SEC EDGAR • companyfacts
      {status.degradedReason && (
        <div className="mt-1 text-warning">{status.degradedReason}</div>
      )}
    </div>
  );
};

export const BalanceSheetPanel: React.FC<BalanceSheetPanelProps> = ({
  data,
  onRunCommand,
}) => {
  const [mappingEditor, setMappingEditor] = React.useState<{
    cell: MappingCellInfo;
    top: number;
    left: number;
  } | null>(null);
  const [showSuccessToast, setShowSuccessToast] = React.useState(false);
  const [selectedStart, setSelectedStart] = React.useState(
    data.selectedPeriodStart ?? '',
  );
  const [selectedEnd, setSelectedEnd] = React.useState(
    data.selectedPeriodEnd ?? '',
  );
  const [selectedCurrency, setSelectedCurrency] = React.useState(
    data.selectedCurrency ?? data.availableCurrencies[0] ?? '',
  );
  const [selectedUnit, setSelectedUnit] = React.useState<UnitOption>('auto');
  const toastTimeoutRef = React.useRef<ReturnType<typeof setTimeout> | null>(
    null,
  );
  const headerCurrency =
    data.selectedCurrency ?? data.availableCurrencies[0] ?? undefined;
  const effectiveUnit: UnitScale =
    selectedUnit === 'auto'
      ? computeAutoUnit(data.periods.map((p) => p.totalAssets))
      : selectedUnit;

  const hasRangeControls =
    data.availablePeriods.length > 0 &&
    Boolean(data.selectedPeriodStart) &&
    Boolean(data.selectedPeriodEnd);
  const resolvedCurrency =
    selectedCurrency || data.selectedCurrency || data.availableCurrencies[0];

  React.useEffect(() => {
    return () => {
      if (toastTimeoutRef.current) {
        clearTimeout(toastTimeoutRef.current);
      }
    };
  }, []);

  React.useEffect(() => {
    setMappingEditor(null);
  }, [data.symbol, data.frequency]);

  React.useEffect(() => {
    setSelectedStart((current) =>
      current === (data.selectedPeriodStart ?? '')
        ? current
        : (data.selectedPeriodStart ?? ''),
    );
    setSelectedEnd((current) =>
      current === (data.selectedPeriodEnd ?? '')
        ? current
        : (data.selectedPeriodEnd ?? ''),
    );
  }, [data.selectedPeriodEnd, data.selectedPeriodStart]);

  React.useEffect(() => {
    setSelectedCurrency((current) =>
      current === (data.selectedCurrency ?? data.availableCurrencies[0] ?? '')
        ? current
        : (data.selectedCurrency ?? data.availableCurrencies[0] ?? ''),
    );
  }, [data.availableCurrencies, data.selectedCurrency]);

  const commitRange = React.useCallback(
    (start: string, end: string, currency = resolvedCurrency) => {
      if (!onRunCommand || !start || !end) {
        return;
      }

      if (
        start === (data.selectedPeriodStart ?? '') &&
        end === (data.selectedPeriodEnd ?? '')
      ) {
        return;
      }

      const nextCommand = buildBalanceSheetCommand(data.symbol, data.frequency, {
        start,
        end,
        currency,
      });
      onRunCommand(nextCommand);
    },
    [
      data.frequency,
      data.selectedPeriodEnd,
      data.selectedPeriodStart,
      data.symbol,
      onRunCommand,
      resolvedCurrency,
    ],
  );

  const handleStartChange = React.useCallback(
    (nextStart: string) => {
      const effectiveEnd = selectedEnd || nextStart;
      if (nextStart > effectiveEnd) {
        setSelectedStart(effectiveEnd);
        setSelectedEnd(nextStart);
        commitRange(effectiveEnd, nextStart);
      } else {
        setSelectedStart(nextStart);
        setSelectedEnd(effectiveEnd);
        commitRange(nextStart, effectiveEnd);
      }
    },
    [commitRange, selectedEnd],
  );

  const handleEndChange = React.useCallback(
    (nextEnd: string) => {
      const effectiveStart = selectedStart || nextEnd;
      if (effectiveStart > nextEnd) {
        setSelectedStart(nextEnd);
        setSelectedEnd(effectiveStart);
        commitRange(nextEnd, effectiveStart);
      } else {
        setSelectedStart(effectiveStart);
        setSelectedEnd(nextEnd);
        commitRange(effectiveStart, nextEnd);
      }
    },
    [commitRange, selectedStart],
  );

  const handleOpenMappingEditor = React.useCallback((cell: MappingCellInfo) => {
    setMappingEditor({
      cell,
      top: 200,
      left: 400,
    });
  }, []);

  const handleMappingSuccess = React.useCallback(() => {
    if (toastTimeoutRef.current) {
      clearTimeout(toastTimeoutRef.current);
    }

    setShowSuccessToast(true);
    toastTimeoutRef.current = setTimeout(() => {
      setShowSuccessToast(false);
      toastTimeoutRef.current = null;
    }, 3000);
  }, []);

  const handleCurrencyChange = React.useCallback(
    (nextCurrency: string) => {
      const normalizedCurrency = nextCurrency.toUpperCase();
      setSelectedCurrency(normalizedCurrency);

      if (!onRunCommand) {
        return;
      }

      onRunCommand(
        buildBalanceSheetCommand(data.symbol, data.frequency, {
          start: selectedStart || data.selectedPeriodStart,
          end: selectedEnd || data.selectedPeriodEnd,
          currency: normalizedCurrency,
        }),
      );
    },
    [
      data.frequency,
      data.selectedPeriodEnd,
      data.selectedPeriodStart,
      data.symbol,
      onRunCommand,
      selectedEnd,
      selectedStart,
    ],
  );

  return (
    <div className="balance-sheet-panel overflow-auto py-4">
      <header className="mb-4">
        <div className="flex items-start justify-between">
          <div>
            <h2 className="text-heading-lg text-term-text">
              {data.symbol} Balance Sheet
            </h2>
            <p className="mt-1 text-body-xs text-term-text-muted">
              {data.companyName} • {data.frequency}
            </p>
            {headerCurrency && (
              <div className="mt-3 flex items-center gap-2 text-body-xs text-term-text-muted">
                <span className="font-mono uppercase tracking-[0.18em] text-[10px]">
                  Currency
                </span>
                {data.availableCurrencies.length > 1 && onRunCommand ? (
                  <select
                    aria-label="Balance sheet currency"
                    className="rounded-md border border-term-border-subtle bg-term-bg px-2 py-1 text-term-text"
                    onChange={(event) =>
                      handleCurrencyChange(event.currentTarget.value)
                    }
                    value={selectedCurrency}
                  >
                    {data.availableCurrencies.map((currency) => (
                      <option key={currency} value={currency}>
                        {currency}
                      </option>
                    ))}
                  </select>
                ) : (
                  <span className="rounded border border-term-border-subtle bg-term-bg-secondary/40 px-2 py-1 font-mono text-term-text">
                    {headerCurrency}
                  </span>
                )}
              </div>
            )}
            <div className="mt-1 flex items-center gap-2 text-body-xs text-term-text-muted">
              <span className="font-mono uppercase tracking-[0.18em] text-[10px]">
                Units
              </span>
              <select
                aria-label="Balance sheet units"
                className="rounded-md border border-term-border-subtle bg-term-bg px-2 py-1 text-term-text"
                onChange={(event) =>
                  setSelectedUnit(event.currentTarget.value as UnitOption)
                }
                value={selectedUnit}
              >
                {UNIT_OPTIONS.map((opt) => (
                  <option key={opt.value} value={opt.value}>
                    {opt.label}
                  </option>
                ))}
              </select>
            </div>
          </div>
          <div className="text-right text-body-xs">
            {data.latestFiling && (
              <div className="mt-1 text-term-text-tertiary">
                {data.latestFiling.form} filed {data.latestFiling.filingDate}
              </div>
            )}
          </div>
        </div>
      </header>

      <section>
        {hasRangeControls && (
          <div className="mb-4 rounded-lg border border-term-border-subtle bg-term-bg-secondary/40 px-3 py-3">
            <div className="mb-3 text-[10px] font-mono uppercase tracking-[0.18em] text-term-text-muted">
              Reported Range
            </div>
            <div className="grid gap-3 md:grid-cols-2">
              <label className="block text-body-xs text-term-text-muted">
                <span className="mb-1 block font-mono uppercase tracking-[0.18em] text-[10px]">
                  Start Period
                </span>
                <select
                  aria-label="Start balance sheet period"
                  className="w-full rounded-md border border-term-border-subtle bg-term-bg px-3 py-2 text-term-text"
                  onChange={(event) =>
                    handleStartChange(event.currentTarget.value)
                  }
                  value={selectedStart}
                >
                  {data.availablePeriods.map((period) => (
                    <option key={period.id} value={period.id}>
                      {period.label}
                    </option>
                  ))}
                </select>
              </label>
              <label className="block text-body-xs text-term-text-muted">
                <span className="mb-1 block font-mono uppercase tracking-[0.18em] text-[10px]">
                  End Period
                </span>
                <select
                  aria-label="End balance sheet period"
                  className="w-full rounded-md border border-term-border-subtle bg-term-bg px-3 py-2 text-term-text"
                  onChange={(event) =>
                    handleEndChange(event.currentTarget.value)
                  }
                  value={selectedEnd}
                >
                  {data.availablePeriods.map((period) => (
                    <option key={period.id} value={period.id}>
                      {period.label}
                    </option>
                  ))}
                </select>
              </label>
            </div>
          </div>
        )}
        <div className="mb-2 text-[10px] font-mono uppercase tracking-[0.18em] text-term-text-muted">
          Values in {unitLabel(effectiveUnit)}{headerCurrency ? ` \u00B7 ${headerCurrency}` : ''}
        </div>
        <StatementTableMinimal
          periods={data.periods}
          enableMappingCustomizer={true}
          onMapField={handleOpenMappingEditor}
          metrics={[
            {
              key: 'cash',
              label: 'Cash & Equivalents',
              mappable: true,
              render: (period) =>
                formatScaled(period.cashAndEquivalents, effectiveUnit),
            },
            {
              key: 'shortTermInvestments',
              label: 'Short-Term Investments',
              mappable: true,
              render: (period) =>
                formatScaled(period.shortTermInvestments, effectiveUnit),
            },
            {
              key: 'accountsReceivableNet',
              label: 'Accounts Receivable, Net',
              mappable: true,
              render: (period) =>
                formatScaled(period.accountsReceivableNet, effectiveUnit),
            },
            {
              key: 'inventory',
              label: 'Inventory',
              mappable: true,
              render: (period) =>
                formatScaled(period.inventory, effectiveUnit),
            },
            {
              key: 'otherCurrentAssets',
              label: 'Other Current Assets',
              mappable: true,
              render: (period) =>
                formatScaled(period.otherCurrentAssets, effectiveUnit),
            },
            {
              key: 'totalCurrentAssets',
              label: 'Total Current Assets',
              mappable: true,
              render: (period) =>
                formatScaled(period.totalCurrentAssets, effectiveUnit),
            },
            {
              key: 'propertyPlantAndEquipmentNet',
              label: 'Property, Plant & Equipment, Net',
              mappable: true,
              render: (period) =>
                formatScaled(
                  period.propertyPlantAndEquipmentNet,
                  effectiveUnit,
                ),
            },
            {
              key: 'goodwill',
              label: 'Goodwill',
              mappable: true,
              render: (period) =>
                formatScaled(period.goodwill, effectiveUnit),
            },
            {
              key: 'intangibleAssets',
              label: 'Intangible Assets',
              mappable: true,
              render: (period) =>
                formatScaled(period.intangibleAssets, effectiveUnit),
            },
            {
              key: 'otherNonCurrentAssets',
              label: 'Other Non-Current Assets',
              mappable: true,
              render: (period) =>
                formatScaled(period.otherNonCurrentAssets, effectiveUnit),
            },
            {
              key: 'totalAssets',
              label: 'Total Assets',
              mappable: true,
              render: (period) =>
                formatScaled(period.totalAssets, effectiveUnit),
            },
            {
              key: 'accountsPayable',
              label: 'Accounts Payable',
              mappable: true,
              render: (period) =>
                formatScaled(period.accountsPayable, effectiveUnit),
            },
            {
              key: 'accruedExpensesAndOtherCurrentLiabilities',
              label: 'Accrued Expenses & Other Current Liabilities',
              mappable: true,
              render: (period) =>
                formatScaled(
                  period.accruedExpensesAndOtherCurrentLiabilities,
                  effectiveUnit,
                ),
            },
            {
              key: 'shortTermDebt',
              label: 'Short-Term Debt',
              mappable: true,
              render: (period) =>
                formatScaled(period.shortTermDebt, effectiveUnit),
            },
            {
              key: 'totalCurrentLiabilities',
              label: 'Total Current Liabilities',
              mappable: true,
              render: (period) =>
                formatScaled(period.totalCurrentLiabilities, effectiveUnit),
            },
            {
              key: 'longTermDebt',
              label: 'Long-Term Debt',
              mappable: true,
              render: (period) =>
                formatScaled(period.longTermDebt, effectiveUnit),
            },
            {
              key: 'otherNonCurrentLiabilities',
              label: 'Other Non-Current Liabilities',
              mappable: true,
              render: (period) =>
                formatScaled(
                  period.otherNonCurrentLiabilities,
                  effectiveUnit,
                ),
            },
            {
              key: 'totalLiabilities',
              label: 'Total Liabilities',
              mappable: true,
              render: (period) =>
                formatScaled(period.totalLiabilities, effectiveUnit),
            },
            {
              key: 'retainedEarnings',
              label: 'Retained Earnings',
              mappable: true,
              render: (period) =>
                formatScaled(period.retainedEarnings, effectiveUnit),
            },
            {
              key: 'accumulatedOtherComprehensiveIncomeLoss',
              label: 'Accumulated OCI',
              mappable: true,
              render: (period) =>
                formatScaled(
                  period.accumulatedOtherComprehensiveIncomeLoss,
                  effectiveUnit,
                ),
            },
            {
              key: 'totalEquity',
              label: 'Total Equity',
              mappable: true,
              render: (period) =>
                formatScaled(period.totalEquity, effectiveUnit),
            },
            {
              key: 'sharesOutstanding',
              label: 'Shares Outstanding',
              mappable: true,
              render: (period) => formatNumber(period.sharesOutstanding),
            },
            {
              key: 'bookValuePerShare',
              label: 'Book Value / Share',
              render: (period) =>
                formatScaled(period.bookValuePerShare, effectiveUnit),
            },
          ]}
        />
      </section>

      <footer className="mt-4 border-t border-term-border-subtle pt-4">
        <SourceAttribution status={data.sourceStatus} />
        {data.mappingWarnings && data.mappingWarnings.length > 0 && (
            <div className="mt-2 rounded border border-warning/30 bg-warning/5 px-3 py-2">
            <div className="mb-1 text-[11px] font-mono font-semibold text-warning">
              Mapping &amp; Calculation Warnings
            </div>
            <ul className="list-inside list-disc text-[11px] font-mono text-term-text-muted">
              {data.mappingWarnings.map((warning, index) => (
                <li key={index}>{scaleWarningNumbers(warning, effectiveUnit)}</li>
              ))}
            </ul>
          </div>
        )}
      </footer>

      {showSuccessToast && (
        <div
          className="fixed bottom-4 right-4 z-50 rounded-md border border-success-border bg-success-bg px-4 py-3 shadow-lg"
          aria-live="polite"
          role="status"
        >
          <div className="flex items-center gap-3">
            <div className="text-success-text">
              <svg
                className="h-5 w-5"
                fill="none"
                stroke="currentColor"
                viewBox="0 0 24 24"
              >
                <path
                  strokeLinecap="round"
                  strokeLinejoin="round"
                  strokeWidth={2}
                  d="M5 13l4 4L19 7"
                />
              </svg>
            </div>
            <div>
              <p className="text-sm font-medium text-success-text">
                Mapping saved successfully
              </p>
              <p className="mt-1 text-xs text-success-text-muted">
                Balance sheet data is being refreshed...
              </p>
            </div>
          </div>
        </div>
      )}

      {mappingEditor && (
        <>
          <div
            className="fixed inset-0 z-40 bg-black/20"
            onClick={() => setMappingEditor(null)}
            onKeyDown={(event) => {
              if (
                event.key === 'Escape' ||
                event.key === 'Enter' ||
                event.key === ' '
              ) {
                setMappingEditor(null);
              }
            }}
            role="button"
            tabIndex={0}
            aria-label="Close mapping editor"
            style={{ pointerEvents: 'auto' }}
          />
          <InlineMappingEditor
            key={`${mappingEditor.cell.metricKey}-${mappingEditor.cell.metricLabel}`}
            cellInfo={mappingEditor.cell}
            context={{
              symbol: data.symbol,
              frequency: data.frequency,
              earliestPeriod: data.periods[data.periods.length - 1]?.periodEnd,
              latestPeriod: data.periods[0]?.periodEnd,
            }}
            availableConcepts={data.availableConcepts}
            onSuccess={handleMappingSuccess}
            onClose={() => setMappingEditor(null)}
            position={{ top: mappingEditor.top, left: mappingEditor.left }}
          />
        </>
      )}
    </div>
  );
};
