import { useMemo, useState } from 'react';
import type {
  FinancialModel,
  ModelWorkbook,
  ModelWorkbookCell,
  ModelWorkbookSheet,
} from '../../../types/research';
import { addressToCellPosition, cellPositionToAddress } from '../../../lib/modelWorkbookAdapter';

interface UniverModelGridProps {
  model: FinancialModel;
  activeSheetId: string | null;
  onActiveSheetChange: (sheetId: string) => void;
  onWorkbookChange: (workbook: ModelWorkbook) => void;
}

const MIN_VISIBLE_ROWS = 28;
const MIN_VISIBLE_COLUMNS = 9;

const formatDisplayValue = (cell: ModelWorkbookCell | undefined) => {
  if (!cell) {
    return '';
  }
  if (cell.formula) {
    return cell.formula;
  }
  if (cell.value === null || cell.value === undefined) {
    return '';
  }
  return String(cell.value);
};

const parseInputValue = (
  rawValue: string,
  previousCell: ModelWorkbookCell | undefined,
): ModelWorkbookCell | null => {
  const value = rawValue.trim();
  if (!value) {
    return previousCell?.cellId || previousCell?.binding || previousCell?.format
      ? {
          ...(previousCell?.format ? { format: previousCell.format } : {}),
          ...(previousCell?.cellId ? { cellId: previousCell.cellId } : {}),
          ...(previousCell?.binding ? { binding: previousCell.binding } : {}),
        }
      : null;
  }

  const base = {
    ...(previousCell?.format ? { format: previousCell.format } : {}),
    ...(previousCell?.cellId ? { cellId: previousCell.cellId } : {}),
    ...(previousCell?.binding ? { binding: previousCell.binding } : {}),
  };

  if (value.startsWith('=')) {
    return { ...base, formula: value };
  }

  const normalizedPercent = value.endsWith('%')
    ? Number(value.slice(0, -1).replace(/,/g, '')) / 100
    : null;
  if (normalizedPercent !== null && Number.isFinite(normalizedPercent)) {
    return { ...base, value: normalizedPercent, format: previousCell?.format ?? 'percent' };
  }

  const normalizedNumber = Number(value.replace(/,/g, ''));
  if (Number.isFinite(normalizedNumber) && value !== '') {
    return { ...base, value: normalizedNumber };
  }

  return { ...base, value };
};

const getGridBounds = (sheet: ModelWorkbookSheet | undefined) => {
  let maxRow = MIN_VISIBLE_ROWS - 1;
  let maxColumn = MIN_VISIBLE_COLUMNS - 1;

  Object.keys(sheet?.cells ?? {}).forEach((address) => {
    const position = addressToCellPosition(address);
    if (!position) {
      return;
    }
    maxRow = Math.max(maxRow, position.row);
    maxColumn = Math.max(maxColumn, position.column);
  });

  return {
    rows: Array.from({ length: maxRow + 1 }, (_, index) => index),
    columns: Array.from({ length: maxColumn + 1 }, (_, index) => index),
  };
};

const getCellClassName = (cell: ModelWorkbookCell | undefined, row: number, column: number) => {
  const classes = [
    'min-w-[112px]',
    'border-r',
    'border-b',
    'border-term-border',
    'px-2',
    'py-1.5',
    'align-middle',
  ];

  if (column === 0) {
    classes.push('min-w-[220px]', 'font-medium', 'text-term-text');
  } else {
    classes.push('text-right', 'font-mono');
  }

  if (row === 0 || row === 2) {
    classes.push('bg-term-panel', 'font-semibold', 'text-term-text');
  } else if (cell?.cellId) {
    classes.push('bg-blue-500/10');
  } else if (cell?.formula) {
    classes.push('bg-term-panel/50', 'text-term-text-muted');
  } else {
    classes.push('bg-term-bg', 'text-term-text');
  }

  if (cell?.binding) {
    classes.push('shadow-[inset_3px_0_0_rgba(59,130,246,0.65)]');
  }

  return classes.join(' ');
};

export const UniverModelGrid = ({
  model,
  activeSheetId,
  onActiveSheetChange,
  onWorkbookChange,
}: UniverModelGridProps) => {
  const [selectedAddress, setSelectedAddress] = useState<string | null>(null);
  const sheet =
    model.workbookJson.sheets.find(
      (candidate) => candidate.id === (activeSheetId ?? model.workbookJson.activeSheetId),
    ) ?? model.workbookJson.sheets[0];

  const bounds = useMemo(() => getGridBounds(sheet), [sheet]);

  const updateCell = (address: string, rawValue: string) => {
    if (!sheet) {
      return;
    }
    const previousCell = sheet.cells[address];
    const nextCell = parseInputValue(rawValue, previousCell);
    const nextCells = { ...sheet.cells };

    if (nextCell) {
      nextCells[address] = nextCell;
    } else {
      delete nextCells[address];
    }

    const nextWorkbook: ModelWorkbook = {
      ...model.workbookJson,
      activeSheetId: sheet.id,
      sheets: model.workbookJson.sheets.map((candidate) =>
        candidate.id === sheet.id
          ? {
              ...candidate,
              cells: nextCells,
            }
          : candidate,
      ),
    };

    onActiveSheetChange(sheet.id);
    onWorkbookChange(nextWorkbook);
  };

  if (!sheet) {
    return (
      <div className="flex min-h-[420px] items-center justify-center bg-term-bg text-sm text-term-text-muted">
        No workbook sheet available.
      </div>
    );
  }

  return (
    <div className="min-h-0 flex-1 bg-term-bg">
      <div className="flex items-center justify-between border-b border-term-border px-4 py-2 text-xs text-term-text-muted">
        <div>
          Active sheet: <span className="font-medium text-term-text">{sheet.name}</span>
        </div>
        {selectedAddress ? (
          <div className="font-mono">
            {sheet.id} {selectedAddress}
          </div>
        ) : null}
      </div>
      <div className="h-[560px] min-h-[420px] overflow-auto">
        <table className="w-max min-w-full border-collapse text-sm">
          <thead className="sticky top-0 z-10">
            <tr>
              <th className="sticky left-0 z-20 w-12 border-r border-b border-term-border bg-term-panel px-2 py-1.5 text-xs font-medium text-term-text-muted">
                #
              </th>
              {bounds.columns.map((column) => (
                <th
                  key={column}
                  className="min-w-[112px] border-r border-b border-term-border bg-term-panel px-2 py-1.5 text-center font-mono text-xs font-medium text-term-text-muted"
                >
                  {cellPositionToAddress(0, column).replace(/\d+$/, '')}
                </th>
              ))}
            </tr>
          </thead>
          <tbody>
            {bounds.rows.map((row) => (
              <tr key={row}>
                <th className="sticky left-0 z-10 w-12 border-r border-b border-term-border bg-term-panel px-2 py-1.5 text-right font-mono text-xs font-medium text-term-text-muted">
                  {row + 1}
                </th>
                {bounds.columns.map((column) => {
                  const address = cellPositionToAddress(row, column);
                  const cell = sheet.cells[address];
                  return (
                    <td key={address} className={getCellClassName(cell, row, column)}>
                      <input
                        aria-label={`${sheet.name} ${address}`}
                        className="h-7 w-full bg-transparent text-inherit outline-none placeholder:text-term-text-muted/50 focus:bg-term-surface focus:ring-1 focus:ring-term-accent"
                        defaultValue={formatDisplayValue(cell)}
                        onFocus={() => setSelectedAddress(address)}
                        onBlur={(event) => updateCell(address, event.currentTarget.value)}
                        onKeyDown={(event) => {
                          if (event.key === 'Enter') {
                            event.currentTarget.blur();
                          }
                        }}
                      />
                    </td>
                  );
                })}
              </tr>
            ))}
          </tbody>
        </table>
      </div>
    </div>
  );
};
