"""Simplified GOST A4 PDF export with frame and table."""

from __future__ import annotations

from io import BytesIO
from pathlib import Path
from typing import Any

from reportlab.lib.pagesizes import A4
from reportlab.lib.units import mm
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
from reportlab.pdfgen import canvas

from app.core.config import get_settings

_font_registered = False
FONT_NAME = "GOST_A"


def _ensure_font() -> str:
    global _font_registered
    if not _font_registered:
        path = Path(get_settings().font_path)
        if path.exists():
            pdfmetrics.registerFont(TTFont(FONT_NAME, str(path)))
            _font_registered = True
            return FONT_NAME
        return "Helvetica"
    return FONT_NAME if Path(get_settings().font_path).exists() else "Helvetica"


DOC_TITLES = {
    "perechen": "Перечень элементов",
    "specification_pcb": "Спецификация",
    "specification": "Спецификация",
    "vedomost": "Ведомость покупных изделий",
}

COLUMNS = {
    "perechen": [
        ("position", 30 * mm, "Поз."),
        ("designation", 100 * mm, "Наименование"),
        ("quantity", 15 * mm, "Кол."),
        ("note", 35 * mm, "Прим."),
    ],
    "specification_pcb": [
        ("format", 12 * mm, "Форм."),
        ("zone", 10 * mm, "Зона"),
        ("position", 10 * mm, "Поз."),
        ("designation", 40 * mm, "Обозн."),
        ("name", 55 * mm, "Наименование"),
        ("quantity", 12 * mm, "Кол."),
        ("note", 30 * mm, "Прим."),
    ],
    "specification": [
        ("format", 12 * mm, "Форм."),
        ("zone", 10 * mm, "Зона"),
        ("position", 10 * mm, "Поз."),
        ("designation", 40 * mm, "Обозн."),
        ("name", 55 * mm, "Наименование"),
        ("quantity", 12 * mm, "Кол."),
        ("note", 30 * mm, "Прим."),
    ],
    "vedomost": [
        ("name", 40 * mm, "Наименование"),
        ("product_code", 20 * mm, "Код"),
        ("document_code", 25 * mm, "Док."),
        ("supplier", 20 * mm, "Пост."),
        ("where_used", 20 * mm, "Куда"),
        ("quantity_per_item", 12 * mm, "На изд."),
        ("total_quantity", 12 * mm, "Всего"),
        ("note", 20 * mm, "Прим."),
    ],
}

ROWS_FIRST = {"perechen": 25, "specification_pcb": 26, "specification": 27, "vedomost": 24}
ROWS_OTHER = {"perechen": 32, "specification_pcb": 32, "specification": 33, "vedomost": 29}


def _draw_frame(c: canvas.Canvas, w: float, h: float, page: int, total: int, inscriptions: dict[int, str], doc_type: str):
    font = _ensure_font()
    margin_left = 20 * mm
    margin_right = 5 * mm
    margin_top = 5 * mm
    margin_bottom = 5 * mm
    c.setLineWidth(0.8)
    c.rect(margin_left, margin_bottom, w - margin_left - margin_right, h - margin_top - margin_bottom)

    # Title block (simplified bottom-right)
    block_h = 55 * mm if page == 1 else 15 * mm
    block_w = 185 * mm
    x0 = w - margin_right - block_w
    y0 = margin_bottom
    c.setLineWidth(0.5)
    c.rect(x0, y0, block_w, block_h)

    c.setFont(font, 8)
    name = inscriptions.get(1, "")
    designation = inscriptions.get(2, "")
    org = inscriptions.get(9, "")
    title = DOC_TITLES.get(doc_type, "")
    c.drawString(x0 + 2 * mm, y0 + block_h - 6 * mm, f"{title}")
    c.drawString(x0 + 2 * mm, y0 + block_h - 12 * mm, designation[:60])
    c.drawString(x0 + 2 * mm, y0 + block_h - 18 * mm, name[:60])
    if page == 1:
        c.drawString(x0 + 2 * mm, y0 + 8 * mm, org[:40])
        c.drawString(x0 + 2 * mm, y0 + 3 * mm, f"Разраб. {inscriptions.get(111, '')}")
        c.drawString(x0 + 50 * mm, y0 + 3 * mm, f"Пров. {inscriptions.get(112, '')}")
    c.drawRightString(x0 + block_w - 2 * mm, y0 + 3 * mm, f"Лист {page}/{total}")


def _chunk_rows(rows: list[dict[str, Any]], first: int, other: int) -> list[list[dict[str, Any]]]:
    if not rows:
        return [[]]
    pages: list[list[dict[str, Any]]] = []
    i = 0
    limit = first
    while i < len(rows):
        pages.append(rows[i : i + limit])
        i += limit
        limit = other
    return pages


def export_pdf(
    table_type: str,
    rows: list[dict[str, Any]],
    inscriptions: dict[int, str] | None = None,
) -> bytes:
    if table_type == "simple_list":
        raise ValueError("PDF export is not available for simple_list")
    inscriptions = inscriptions or {}
    font = _ensure_font()
    cols = COLUMNS[table_type]
    first = ROWS_FIRST[table_type]
    other = ROWS_OTHER[table_type]
    pages = _chunk_rows(rows, first, other)
    total = max(len(pages), 1)

    buf = BytesIO()
    c = canvas.Canvas(buf, pagesize=A4)
    w, h = A4

    for page_idx, page_rows in enumerate(pages, start=1):
        _draw_frame(c, w, h, page_idx, total, inscriptions, table_type)

        # table area
        left = 20 * mm
        top = h - 10 * mm
        row_h = 6 * mm
        header_y = top - 8 * mm

        # column headers
        x = left + 2 * mm
        c.setFont(font, 7)
        for field, width, label in cols:
            c.drawString(x, header_y, label)
            x += width
        c.line(left, header_y - 2 * mm, left + sum(w for _, w, _ in cols) + 4 * mm, header_y - 2 * mm)

        y = header_y - row_h
        for row in page_rows:
            if y < 65 * mm and page_idx == 1:
                break
            if y < 25 * mm:
                break
            x = left + 2 * mm
            style_size = 8 if row.get("is_header") else 7
            c.setFont(font, style_size)
            for field, width, _ in cols:
                text = "" if row.get("is_empty") else str(row.get(field, "") or "")
                # truncate to fit roughly
                max_chars = max(int(width / mm), 1)
                c.drawString(x, y, text[: max_chars + 5])
                x += width
            y -= row_h

        c.showPage()

    c.save()
    return buf.getvalue()
