import type { SpreadsheetColumnConfig } from '../types';
import {
  COLUMN_LETTER_HEIGHT,
  DEFAULT_COL_WIDTH,
  DEFAULT_ROW_HEIGHT,
  MIN_COL_WIDTH,
  ROW_NUMBER_WIDTH,
} from '../types';
import { getDataColX } from '../canvas/columnLayout';

const CELL_PADDING = 16;
const SAMPLE_ROWS = 50;

function measureTextWidth(
  ctx: CanvasRenderingContext2D,
  text: string,
): number {
  return ctx.measureText(text).width + CELL_PADDING;
}

function formatCellDisplay(value: unknown, cellType: import('../types').CellType): string {  if (value === null || value === undefined) return '';
  if (cellType === 'number') {
    const n = Number(value);
    return Number.isFinite(n) ? String(n) : String(value);
  }
  if (typeof value === 'object') return JSON.stringify(value);
  return String(value);
}

export function measureColumnWidths(
  canvas: HTMLCanvasElement,
  headers: Array<{ title: string; col: number }>,
  columns: SpreadsheetColumnConfig[],
  rows: Record<string, unknown>[],
  defaultWidth: number,
  resolveDisplayValue?: (
    dataRowIndex: number,
    colCfg: SpreadsheetColumnConfig,
    row: Record<string, unknown>,
  ) => unknown,
  formatWithSuffix?: (
    value: unknown,
    colCfg: SpreadsheetColumnConfig,
  ) => string,
): number[] {  const ctx = canvas.getContext('2d');
  if (!ctx) return headers.map(() => defaultWidth);

  ctx.font = '13px -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif';

  const maxCol = Math.max(...headers.map((h) => h.col), 0);
  const widths = new Array<number>(maxCol + 1).fill(defaultWidth);

  for (const header of headers) {
    widths[header.col] = Math.max(
      widths[header.col] ?? defaultWidth,
      measureTextWidth(ctx, header.title),
      MIN_COL_WIDTH,
    );
  }

  const sample = rows.slice(0, SAMPLE_ROWS);
  for (const colCfg of columns) {
    let maxW = widths[colCfg.col] ?? defaultWidth;
    sample.forEach((row, dataRowIdx) => {
      const raw = resolveDisplayValue
        ? resolveDisplayValue(dataRowIdx, colCfg, row)
        : row[colCfg.fieldId];
      const text = formatWithSuffix
        ? formatWithSuffix(raw, colCfg)
        : formatCellDisplay(raw, colCfg.cellType === 'formula' ? 'number' : colCfg.cellType);
      maxW = Math.max(maxW, measureTextWidth(ctx, text));
    });
    widths[colCfg.col] = Math.max(maxW, MIN_COL_WIDTH);
  }
  return widths;
}

export function getRowHeight(
  cellType: import('../types').CellType,  configured: number | 'auto' | undefined,
): number {
  if (typeof configured === 'number') return configured;
  switch (cellType) {
    case 'image':
    case 'video':
      return 48;
    default:
      return DEFAULT_ROW_HEIGHT;
  }
}

export function getTotalWidth(colWidths: number[]): number {
  return colWidths.reduce((sum, w) => sum + w, 0);
}

export function getRowTop(rowIndex: number, rowHeight: number): number {
  return rowIndex * rowHeight;
}

export function getColLeft(colIndex: number, colWidths: number[]): number {
  let left = 0;
  for (let i = 0; i < colIndex; i += 1) {
    left += colWidths[i] ?? DEFAULT_COL_WIDTH;
  }
  return left;
}

function getDataColScreenX(
  col: number,
  colWidths: number[],
  scrollLeft: number,
  fixedCols: number[],
  fixedWidth: number,
): number {
  return getDataColX(col, colWidths, scrollLeft, fixedCols, fixedWidth);
}

export function hitTestCell(
  x: number,
  y: number,
  scrollTop: number,
  scrollLeft: number,
  colWidths: number[],
  rowHeight: number,
  rowCount: number,
  colCount: number,
  fixedCols: number[] = [],
  fixedWidth = ROW_NUMBER_WIDTH,
): { row: number; col: number } | null {
  const bodyY = y + scrollTop;
  if (bodyY < 0) return null;

  const row = Math.floor(bodyY / rowHeight);
  if (row < 0 || row >= rowCount) return null;

  for (let col = 0; col < colCount; col += 1) {
    const cellX = getDataColScreenX(
      col,
      colWidths,
      scrollLeft,
      fixedCols,
      fixedWidth,
    );
    const w = colWidths[col] ?? DEFAULT_COL_WIDTH;
    if (x >= cellX && x < cellX + w) {
      return { row, col };
    }
  }
  return null;
}

export function hitTestRowNumber(
  x: number,
  y: number,
  scrollTop: number,
  rowHeight: number,
  rowCount: number,
): number | null {
  if (x < 0 || x >= ROW_NUMBER_WIDTH) return null;
  const bodyY = y + scrollTop;
  if (bodyY < 0) return null;
  const row = Math.floor(bodyY / rowHeight);
  if (row < 0 || row >= rowCount) return null;
  return row;
}

export type HeaderHitArea = 'corner' | 'columnLetter' | 'columnTitle';

export function hitTestHeaderArea(
  x: number,
  y: number,
  scrollLeft: number,
  colWidths: number[],
  colCount: number,
  fixedCols: number[] = [],
  fixedWidth = ROW_NUMBER_WIDTH,
): { area: HeaderHitArea; col?: number } | null {
  if (x >= 0 && x < ROW_NUMBER_WIDTH) {
    return { area: 'corner' };
  }
  const col = hitTestHeaderCol(
    x,
    scrollLeft,
    colWidths,
    colCount,
    fixedCols,
    fixedWidth,
  );
  if (col === null) return null;
  if (y < COLUMN_LETTER_HEIGHT) {
    return { area: 'columnLetter', col };
  }
  return { area: 'columnTitle', col };
}

export function hitTestHeaderCol(
  x: number,
  scrollLeft: number,
  colWidths: number[],
  colCount: number,
  fixedCols: number[] = [],
  fixedWidth = ROW_NUMBER_WIDTH,
): number | null {
  for (let col = 0; col < colCount; col += 1) {
    const cellX = getDataColScreenX(
      col,
      colWidths,
      scrollLeft,
      fixedCols,
      fixedWidth,
    );
    const w = colWidths[col] ?? DEFAULT_COL_WIDTH;
    if (x >= cellX && x < cellX + w) return col;
  }
  return null;
}

export { getDataColScreenX };

export { formatCellDisplay, CELL_PADDING };
