"""Tests for the amendment (değişiklik gösteren evrak) generator.

Gerçek DOCX üretilir (mock yok); içerik ve endpoint davranışı doğrulanır.
PDF testi soffice gerektirir — soffice yoksa atlanır.
"""

from __future__ import annotations

import io

import pytest
from docx import Document
from httpx import ASGITransport, AsyncClient

from app.main import app
from app.services.docx import (
    AmendmentInput,
    AmendmentItem,
    TermChange,
    build_amendment_docx,
)
from app.services.docx.pdf_converter import soffice_available


def _sample_input() -> AmendmentInput:
    return AmendmentInput(
        application_number="2026/005880",
        application_date="17.04.2026",
        invention_title="POST-KUANTUM KRİPTOGRAFİ DESTEKLİ AĞ GEÇİDİ",
        applicant_name="Örnek Bilişim A.Ş.",
        office_letter_ref="28.04.2026 tarihli, E-12345 sayılı yazı",
        items=[
            AmendmentItem(
                finding_title="İstemlerde alt başlık kullanılması",
                change_made="İstemlerdeki alt başlıklar kaldırıldı.",
            ),
            AmendmentItem(
                finding_title="Özette buluş başlığının bulunmaması",
                change_made="Özet başlığı altına buluş başlığı eklendi.",
            ),
        ],
        term_changes=[
            TermChange(before="handshake", after="el sıkışması (handshake)"),
            TermChange(
                before="dashboard", after="gösterge paneli (dashboard)"
            ),
        ],
    )


def _docx_text(docx_bytes: bytes) -> str:
    doc = Document(io.BytesIO(docx_bytes))
    return "\n".join(p.text for p in doc.paragraphs)


# --- Builder birim testleri -------------------------------------------------


def test_build_amendment_docx_returns_valid_docx() -> None:
    docx_bytes = build_amendment_docx(_sample_input())
    assert docx_bytes[:2] == b"PK"  # ZIP/DOCX imzası
    assert len(docx_bytes) > 1000


def test_amendment_docx_contains_application_number() -> None:
    text = _docx_text(build_amendment_docx(_sample_input()))
    assert "2026/005880" in text


def test_amendment_docx_contains_all_items() -> None:
    text = _docx_text(build_amendment_docx(_sample_input()))
    assert "İstemlerde alt başlık" in text
    assert "Özette buluş başlığı" in text
    # Maddeler numaralandırılmış olmalı
    assert "1." in text
    assert "2." in text


def test_amendment_docx_has_scope_disclaimer() -> None:
    """Evrak 'kapsam aşılmadı' beyanını içermeli — hukuki olarak kritik."""
    text = _docx_text(build_amendment_docx(_sample_input()))
    assert "kapsamını aşma" in text


def test_amendment_docx_term_table_present() -> None:
    """Yabancı terim tablosu DOCX'e tablo olarak eklenmiş olmalı."""
    doc = Document(io.BytesIO(build_amendment_docx(_sample_input())))
    assert len(doc.tables) == 1
    table = doc.tables[0]
    # Başlık satırı + 2 terim = 3 satır
    assert len(table.rows) == 3
    assert "handshake" in table.cell(1, 0).text


def test_amendment_without_term_changes_has_no_table() -> None:
    data = _sample_input()
    data.term_changes = []
    doc = Document(io.BytesIO(build_amendment_docx(data)))
    assert len(doc.tables) == 0


# --- Endpoint testleri ------------------------------------------------------


@pytest.mark.asyncio
async def test_amendment_endpoint_returns_docx() -> None:
    transport = ASGITransport(app=app)
    async with AsyncClient(transport=transport, base_url="http://test") as client:
        resp = await client.post(
            "/api/v1/amendment/generate",
            json=_sample_input().model_dump(),
        )
    assert resp.status_code == 200
    assert resp.content[:2] == b"PK"
    assert "wordprocessingml" in resp.headers["content-type"]
    assert "Degisiklik_Evraki.docx" in resp.headers["content-disposition"]


@pytest.mark.asyncio
async def test_amendment_endpoint_rejects_bad_format() -> None:
    transport = ASGITransport(app=app)
    async with AsyncClient(transport=transport, base_url="http://test") as client:
        resp = await client.post(
            "/api/v1/amendment/generate?fmt=xls",
            json=_sample_input().model_dump(),
        )
    assert resp.status_code == 400


@pytest.mark.asyncio
@pytest.mark.skipif(
    not soffice_available(), reason="LibreOffice (soffice) kurulu değil"
)
async def test_amendment_endpoint_returns_pdf() -> None:
    transport = ASGITransport(app=app)
    async with AsyncClient(transport=transport, base_url="http://test") as client:
        resp = await client.post(
            "/api/v1/amendment/generate?fmt=pdf",
            json=_sample_input().model_dump(),
        )
    assert resp.status_code == 200
    assert resp.content[:5] == b"%PDF-"


# --- EP / US değişiklik evrakı ----------------------------------------------


def test_amendment_epo_uses_english_and_epc_basis() -> None:
    """EP evrakı İngilizce başlık ve EPC dayanağı içermeli."""
    data = _sample_input()
    data.jurisdiction = "EP"
    text = _docx_text(build_amendment_docx(data))
    assert "AMENDMENTS TO THE EUROPEAN PATENT APPLICATION" in text
    assert "Rule 137 EPC" in text
    assert "Article 123(2) EPC" in text


def test_amendment_uspto_uses_english_and_cfr_basis() -> None:
    """US evrakı İngilizce 'AMENDMENT' başlığı ve 37 CFR dayanağı içermeli."""
    data = _sample_input()
    data.jurisdiction = "US"
    text = _docx_text(build_amendment_docx(data))
    assert "AMENDMENT" in text
    assert "37 CFR 1.121" in text
    assert "new matter" in text.lower()


def test_amendment_tr_remains_turkish() -> None:
    """TR evrakı (varsayılan) Türkçe kalmalı — geriye uyum."""
    data = _sample_input()  # jurisdiction varsayılan TR
    text = _docx_text(build_amendment_docx(data))
    assert "TARİFNAME TAKIMINDA YAPILAN DEĞİŞİKLİĞİN" in text
    assert "6769 sayılı" in text


def test_amendment_term_table_only_for_tr() -> None:
    """Yabancı terim tablosu yalnızca TR evrakında bulunur."""
    from docx import Document

    # EP — term_changes verilse bile tablo eklenmemeli
    ep = _sample_input()
    ep.jurisdiction = "EP"
    ep_doc = Document(io.BytesIO(build_amendment_docx(ep)))
    assert len(ep_doc.tables) == 0

    # TR — term_changes varsa tablo eklenmeli
    tr = _sample_input()  # _sample_input term_changes içerir
    tr_doc = Document(io.BytesIO(build_amendment_docx(tr)))
    assert len(tr_doc.tables) == 1


def test_amendment_all_jurisdictions_valid_docx() -> None:
    """Her ofis geçerli DOCX (ZIP imzası) üretmeli."""
    for juris in ("TR", "EP", "US"):
        data = _sample_input()
        data.jurisdiction = juris
        docx = build_amendment_docx(data)
        assert docx[:2] == b"PK", juris


@pytest.mark.asyncio
async def test_amendment_endpoint_accepts_jurisdiction() -> None:
    transport = ASGITransport(app=app)
    payload = _sample_input().model_dump()
    payload["jurisdiction"] = "EP"
    async with AsyncClient(transport=transport, base_url="http://test") as client:
        resp = await client.post(
            "/api/v1/amendment/generate", json=payload
        )
    assert resp.status_code == 200
    assert resp.content[:2] == b"PK"
