import { Typography } from 'antd';
import type { ChatPreviewTarget } from './ChatPreviewBody';

const { Text } = Typography;

type TableCellValue = string;

type TabularPreviewModel = {
  columns: string[];
  rows: TableCellValue[][];
  rowCount: number;
  sourceLabel: string;
};

type ChatDataTablePreviewProps = {
  model: TabularPreviewModel;
};

function stringifyCellValue(value: unknown): TableCellValue {
  if (value === null || value === undefined) {
    return '';
  }

  if (typeof value === 'string') {
    return value;
  }

  if (typeof value === 'number' || typeof value === 'boolean') {
    return String(value);
  }

  try {
    return JSON.stringify(value);
  } catch {
    return String(value);
  }
}

function normalizeObjectRows(rows: Record<string, unknown>[], sourceLabel: string): TabularPreviewModel | null {
  if (!rows.length) {
    return null;
  }

  const columns = Array.from(
    rows.reduce((set, row) => {
      Object.keys(row).forEach((key) => set.add(key));
      return set;
    }, new Set<string>()),
  );

  if (!columns.length) {
    return null;
  }

  return {
    columns,
    rows: rows.map((row) => columns.map((column) => stringifyCellValue(row[column]))),
    rowCount: rows.length,
    sourceLabel,
  };
}

function resolveJsonRows(value: unknown): Record<string, unknown>[] | null {
  if (Array.isArray(value) && value.every((item) => item && typeof item === 'object' && !Array.isArray(item))) {
    return value as Record<string, unknown>[];
  }

  if (value && typeof value === 'object' && !Array.isArray(value)) {
    const entries = Object.values(value as Record<string, unknown>);
    for (const entry of entries) {
      const resolved = resolveJsonRows(entry);
      if (resolved?.length) {
        return resolved;
      }
    }
  }

  return null;
}

function parseCsvLine(line: string) {
  const cells: string[] = [];
  let current = '';
  let quoted = false;

  for (let index = 0; index < line.length; index += 1) {
    const char = line[index] ?? '';
    const nextChar = line[index + 1] ?? '';

    if (char === '"') {
      if (quoted && nextChar === '"') {
        current += '"';
        index += 1;
        continue;
      }

      quoted = !quoted;
      continue;
    }

    if (char === ',' && !quoted) {
      cells.push(current.trim());
      current = '';
      continue;
    }

    current += char;
  }

  cells.push(current.trim());
  return cells;
}

function parseCsvTable(previewText: string, sourceLabel: string): TabularPreviewModel | null {
  const lines = previewText
    .split(/\r?\n/)
    .map((line) => line.trim())
    .filter(Boolean);

  if (lines.length < 2) {
    return null;
  }

  const header = parseCsvLine(lines[0] ?? '');
  if (!header.length || header.every((column) => !column)) {
    return null;
  }

  const rows = lines.slice(1).map((line) => {
    const parsed = parseCsvLine(line);
    return header.map((_, index) => parsed[index] ?? '');
  });

  return {
    columns: header,
    rows,
    rowCount: rows.length,
    sourceLabel,
  };
}

export function resolveTabularPreviewModel(target: ChatPreviewTarget, previewText: string): TabularPreviewModel | null {
  const pathname = target.url.toLowerCase().split('?')[0] ?? '';

  if (pathname.endsWith('.json')) {
    try {
      const parsed = JSON.parse(previewText) as unknown;
      const rows = resolveJsonRows(parsed);
      return rows ? normalizeObjectRows(rows, target.label) : null;
    } catch {
      return null;
    }
  }

  if (pathname.endsWith('.csv')) {
    return parseCsvTable(previewText, target.label);
  }

  return null;
}

export function ChatDataTablePreview({ model }: ChatDataTablePreviewProps) {
  return (
    <div className="app-chat-panel__preview-table">
      <div className="app-chat-panel__preview-table-meta">
        <Text strong>{model.sourceLabel}</Text>
        <Text type="secondary">{`행 ${model.rowCount}개 · 열 ${model.columns.length}개`}</Text>
      </div>
      <div className="app-chat-panel__preview-table-scroll">
        <table className="app-chat-panel__preview-table-grid">
          <thead>
            <tr>
              {model.columns.map((column) => (
                <th key={column}>{column}</th>
              ))}
            </tr>
          </thead>
          <tbody>
            {model.rows.map((row, rowIndex) => (
              <tr key={`${model.sourceLabel}-${rowIndex}`}>
                {row.map((cell, cellIndex) => (
                  <td key={`${model.columns[cellIndex] ?? cellIndex}-${rowIndex}`}>{cell || '-'}</td>
                ))}
              </tr>
            ))}
          </tbody>
        </table>
      </div>
    </div>
  );
}
