"""Excel (.xlsx) renderer — Markdown tables / JSON → openpyxl.

Two input modes:
1. Markdown: each GFM table (| col | col |) becomes a worksheet.
   Non-table text is collected into a "Summary" sheet.
2. JSON: ``{"SheetName": [[row1], [row2], ...]}`` — each key becomes a
   worksheet with the given rows. Detected when content parses as JSON.
"""

from __future__ import annotations

import json
import re
from pathlib import Path
from typing import Any

from openpyxl import Workbook


class ExcelRenderer:
    """Render Markdown tables or JSON data into a .xlsx file via openpyxl."""

    def render(self, markdown_content: str, output_path: Path) -> Path:
        """Render content to .xlsx. Auto-detects JSON vs Markdown input.

        Args:
            markdown_content: Markdown text with GFM tables, OR a JSON string
                of shape ``{"SheetName": [[row], ...]}``.
            output_path: Destination .xlsx path.

        Returns:
            The output_path.
        """
        # Try JSON path first
        stripped = markdown_content.strip()
        if stripped.startswith("{"):
            try:
                data = json.loads(stripped)
                if isinstance(data, dict):
                    return self._render_json(data, output_path)
            except json.JSONDecodeError:
                pass  # Fall through to Markdown parsing

        return self._render_markdown(markdown_content, output_path)

    def _render_json(self, data: dict[str, list[list[Any]]], output_path: Path) -> Path:
        """Render JSON dict {sheet_name: rows} into a multi-sheet workbook."""
        wb = Workbook()
        # Remove the default sheet — we'll create named ones
        default_ws = wb.active
        wb.remove(default_ws)

        for sheet_name, rows in data.items():
            # Truncate sheet name to 31 chars (Excel limit)
            safe_name = sheet_name[:31] if len(sheet_name) > 31 else sheet_name
            ws = wb.create_sheet(title=safe_name or "Sheet")
            for row in rows:
                ws.append(row)

        if not wb.sheetnames:
            wb.create_sheet(title="Sheet1")

        output_path.parent.mkdir(parents=True, exist_ok=True)
        wb.save(str(output_path))
        return output_path

    def _render_markdown(self, content: str, output_path: Path) -> Path:
        """Parse Markdown tables and non-table text into worksheets."""
        wb = Workbook()
        # Use the default sheet as "Summary" for non-table text
        summary_ws = wb.active
        summary_ws.title = "Summary"

        lines = content.splitlines()
        i = 0
        table_count = 0
        has_summary_text = False

        while i < len(lines):
            line = lines[i]
            i += 1

            # Detect GFM table: line starts with | and next line is separator
            if line.lstrip().startswith("|") and i < len(lines) and re.match(
                r"^\s*\|[\s:|-]+\|\s*$", lines[i]
            ):
                table_lines = [line, lines[i]]
                i += 1
                while i < len(lines) and lines[i].lstrip().startswith("|"):
                    table_lines.append(lines[i])
                    i += 1
                table_count += 1
                sheet_name = f"Table{table_count}"
                ws = wb.create_sheet(title=sheet_name)
                self._fill_sheet_from_table(ws, table_lines)
            else:
                # Non-table line → Summary sheet
                if line.strip():
                    summary_ws.append([line])
                    has_summary_text = True

        # If no summary text was added, remove the empty Summary sheet
        # (but only if there are other sheets — keep at least one sheet)
        if not has_summary_text and len(wb.sheetnames) > 1:
            wb.remove(summary_ws)

        output_path.parent.mkdir(parents=True, exist_ok=True)
        wb.save(str(output_path))
        return output_path

    def _fill_sheet_from_table(self, ws: Any, table_lines: list[str]) -> None:
        """Parse GFM table lines and write rows into a worksheet."""
        for idx, line in enumerate(table_lines):
            if idx == 1:
                # Skip separator row (|---|---|)
                continue
            cells = [c.strip() for c in line.strip().strip("|").split("|")]
            ws.append(cells)
