import { useEffect, useMemo, useState } from 'react';
import * as XLSX from 'xlsx';
import { useLanguage } from '../../../providers/language/LanguageContext';
import styles from '../ContentPreview.module.css';

interface ExcelRendererProps {
  blob: Blob;
  fileName: string;
  onError: (message: string) => void;
}

const EXCEL_MIME_TYPES = new Set([
  'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
  'application/vnd.ms-excel',
  'text/csv',
  'application/csv',
]);

export function isExcelMimeType(mimeType?: string, fileName?: string): boolean {
  if (mimeType && EXCEL_MIME_TYPES.has(mimeType)) return true;
  if (fileName && /\.(xlsx|xls|xlsm|xlsb|ods|csv)$/i.test(fileName)) return true;
  return false;
}

interface RenderedCell {
  display: string;
  rawType: 'n' | 's' | 'b' | 'd' | 'e' | 'z' | string;
  rowspan: number;
  colspan: number;
  skip: boolean;
}

interface RenderedSheet {
  name: string;
  cols: number;
  rows: number;
  colWidthsPx: number[];
  rowHeightsPx: (number | null)[];
  cells: RenderedCell[][];
}

function renderSheet(ws: XLSX.WorkSheet, name: string): RenderedSheet {
  const ref = ws['!ref'];
  if (!ref) {
    return { name, cols: 0, rows: 0, colWidthsPx: [], rowHeightsPx: [], cells: [] };
  }

  const range = XLSX.utils.decode_range(ref);
  const rows = range.e.r - range.s.r + 1;
  const cols = range.e.c - range.s.c + 1;

  const cells: RenderedCell[][] = Array.from({ length: rows }, () =>
    Array.from({ length: cols }, () => ({
      display: '',
      rawType: 'z',
      rowspan: 1,
      colspan: 1,
      skip: false,
    })),
  );

  for (let r = 0; r < rows; r++) {
    for (let c = 0; c < cols; c++) {
      const address = XLSX.utils.encode_cell({ r: r + range.s.r, c: c + range.s.c });
      const cell = ws[address] as XLSX.CellObject | undefined;
      if (!cell) continue;
      const display = cell.w ?? (cell.v !== undefined && cell.v !== null ? String(cell.v) : '');
      cells[r][c].display = display;
      cells[r][c].rawType = cell.t ?? 'z';
    }
  }

  const merges = ws['!merges'] ?? [];
  for (const merge of merges) {
    const rs = merge.s.r - range.s.r;
    const cs = merge.s.c - range.s.c;
    const re = merge.e.r - range.s.r;
    const ce = merge.e.c - range.s.c;
    if (rs < 0 || cs < 0 || re >= rows || ce >= cols) continue;

    cells[rs][cs].rowspan = re - rs + 1;
    cells[rs][cs].colspan = ce - cs + 1;

    for (let r = rs; r <= re; r++) {
      for (let c = cs; c <= ce; c++) {
        if (r === rs && c === cs) continue;
        cells[r][c].skip = true;
      }
    }
  }

  const colWidthsPx: number[] = [];
  const colsMeta = ws['!cols'] ?? [];
  for (let c = 0; c < cols; c++) {
    const meta = colsMeta[c + range.s.c];
    if (meta?.wpx) {
      colWidthsPx.push(meta.wpx);
    } else if (meta?.wch) {
      colWidthsPx.push(Math.round(meta.wch * 7 + 8));
    } else if (meta?.width) {
      colWidthsPx.push(Math.round(meta.width * 7 + 8));
    } else {
      colWidthsPx.push(80);
    }
  }

  const rowHeightsPx: (number | null)[] = [];
  const rowsMeta = ws['!rows'] ?? [];
  for (let r = 0; r < rows; r++) {
    const meta = rowsMeta[r + range.s.r];
    if (meta?.hpx) {
      rowHeightsPx.push(meta.hpx);
    } else if (meta?.hpt) {
      rowHeightsPx.push(Math.round((meta.hpt * 4) / 3));
    } else {
      rowHeightsPx.push(null);
    }
  }

  return { name, cols, rows, colWidthsPx, rowHeightsPx, cells };
}

function alignmentForCell(cell: RenderedCell): 'left' | 'right' | 'center' {
  if (cell.rawType === 'n' || cell.rawType === 'd') return 'right';
  if (cell.rawType === 'b') return 'center';
  return 'left';
}

function colLabel(index: number): string {
  let result = '';
  let n = index;
  do {
    result = String.fromCharCode(65 + (n % 26)) + result;
    n = Math.floor(n / 26) - 1;
  } while (n >= 0);
  return result;
}

export function ExcelRenderer({ blob, fileName, onError }: ExcelRendererProps) {
  const { t } = useLanguage();
  const [sheets, setSheets] = useState<RenderedSheet[]>([]);
  const [activeSheet, setActiveSheet] = useState<string | null>(null);
  const [loading, setLoading] = useState(true);
  const [localError, setLocalError] = useState<string | null>(null);

  useEffect(() => {
    let cancelled = false;
    setLoading(true);
    setLocalError(null);

    blob
      .arrayBuffer()
      .then(buffer => {
        const workbook = XLSX.read(buffer, {
          type: 'array',
          cellDates: true,
          cellNF: true,
          cellStyles: true,
        });
        const parsed = workbook.SheetNames.map(name =>
          renderSheet(workbook.Sheets[name], name),
        );
        if (cancelled) return;
        setSheets(parsed);
        setActiveSheet(parsed[0]?.name ?? null);
        setLoading(false);
      })
      .catch(err => {
        if (cancelled) return;
        const msg = err?.message ?? t('Tabelle konnte nicht gerendert werden.');
        setLocalError(msg);
        setLoading(false);
        onError(msg);
      });

    return () => {
      cancelled = true;
    };
  }, [blob, onError, t]);

  const current = useMemo(
    () => sheets.find(s => s.name === activeSheet) ?? null,
    [sheets, activeSheet],
  );

  if (loading) {
    return (
      <div className={styles.textContainer}>
        <div className={styles.textHeader}>
          <span className={styles.textTitle}>{t('Tabelle wird geladen...')}</span>
        </div>
      </div>
    );
  }

  if (localError) {
    return (
      <div className={styles.textContainer}>
        <div className={styles.textHeader}>
          <span className={styles.textTitle}>{fileName}</span>
        </div>
        <div style={{ padding: '1rem', color: 'var(--color-error)' }}>{localError}</div>
      </div>
    );
  }

  return (
    <div className={styles.textContainer}>
      <div className={styles.textHeader}>
        <span className={styles.textTitle}>{fileName}</span>
        {sheets.length > 1 && (
          <div className={styles.excelTabs}>
            {sheets.map(sheet => (
              <button
                key={sheet.name}
                onClick={() => setActiveSheet(sheet.name)}
                className={`${styles.excelTab} ${
                  sheet.name === activeSheet ? styles.excelTabActive : ''
                }`}
              >
                {sheet.name}
              </button>
            ))}
          </div>
        )}
      </div>
      <div className={styles.excelSheet}>
        {current && current.rows > 0 ? (
          <table className={styles.excelTable}>
            <colgroup>
              <col style={{ width: 40 }} />
              {current.colWidthsPx.map((w, i) => (
                <col key={i} style={{ width: w }} />
              ))}
            </colgroup>
            <thead>
              <tr>
                <th className={styles.excelCorner} />
                {current.colWidthsPx.map((_, i) => (
                  <th key={i} className={styles.excelColHeader}>
                    {colLabel(i)}
                  </th>
                ))}
              </tr>
            </thead>
            <tbody>
              {current.cells.map((row, rIdx) => (
                <tr
                  key={rIdx}
                  style={{
                    height: current.rowHeightsPx[rIdx] ?? undefined,
                  }}
                >
                  <th className={styles.excelRowHeader}>{rIdx + 1}</th>
                  {row.map((cell, cIdx) => {
                    if (cell.skip) return null;
                    return (
                      <td
                        key={cIdx}
                        rowSpan={cell.rowspan}
                        colSpan={cell.colspan}
                        className={styles.excelCell}
                        style={{ textAlign: alignmentForCell(cell) }}
                      >
                        {cell.display}
                      </td>
                    );
                  })}
                </tr>
              ))}
            </tbody>
          </table>
        ) : (
          <div style={{ padding: '1rem', color: 'var(--color-text-secondary)' }}>
            {t('Dieses Arbeitsblatt ist leer.')}
          </div>
        )}
      </div>
    </div>
  );
}
