#!/usr/bin/env python3
"""
JingTian-Tracker Sample Document Generator

Generates 7 realistic sample documents for testing the JingTian document
processing pipeline. Uses pre-generated content pools (no LLM needed at runtime).

Usage:
    python generate_samples.py --output ./outputs
    python generate_samples.py --output ./outputs --seed 42

Documents generated:
    1. DOCX - Letter TO client (Client/{name}/)
    2. PDF  - Scanned letter FROM client (Client/{name}/)
    3. PNG  - Email screenshot FROM client (Client/{name}/)
    4. PDF  - IPD filing receipt (Admin/IPD e-filing/)
    5. DOCX - Internal memo (Admin/General Matter/)
    6. XLSX - Invoice schedule (Billing/Draft Bills/)
    7. PDF  - TM registry record (IP/)
    + Copies 2 real PDFs to IP/
"""

import argparse
import json
import random
import shutil
import sys
from datetime import datetime, timedelta
from pathlib import Path

# Document generators
from generators.docx_letter_to_client import generate as gen_letter_to
from generators.pdf_scanned_letter import generate as gen_scanned_letter
from generators.image_email import generate as gen_email_image
from generators.pdf_filing_receipt import generate as gen_filing_receipt
from generators.docx_memo import generate as gen_memo
from generators.xlsx_invoice import generate as gen_invoice
from generators.pdf_tm_record import generate as gen_tm_record

DATA_DIR = Path(__file__).parent / "data"
REAL_PDFS_DIR = Path(__file__).parent / "real_pdfs"


def load_pools():
    """Load all data pools."""
    pools = {}
    for name in ["clients", "trademarks", "names", "content_pools"]:
        path = DATA_DIR / f"{name}.json"
        if not path.exists():
            print(f"Error: {path} not found. Run generate_content_pools.py first.")
            sys.exit(1)
        pools[name] = json.loads(path.read_text(encoding="utf-8"))
    return pools


def random_future_date(min_days=30, max_days=180):
    """Generate a random date in the future."""
    delta = timedelta(days=random.randint(min_days, max_days))
    return (datetime.now() + delta).strftime("%d-%m-%Y")


def random_tm_number():
    """Generate a realistic 9-digit TM number."""
    prefix = random.choice(["306", "307"])
    suffix = str(random.randint(100000, 999999))
    return prefix + suffix


def sanitize_dirname(name):
    """Sanitize a string for use as a directory/file name."""
    # Replace dots at end (Windows issue), replace spaces with underscores
    name = name.replace(" ", "_")
    name = name.rstrip(".")
    # Remove other problematic chars
    for ch in ["<", ">", ":", '"', "/", "\\", "|", "?", "*"]:
        name = name.replace(ch, "")
    return name


def pick_client(pools):
    """Pick a random client with contact info."""
    client = random.choice(pools["clients"]["clients"])
    return client


def pick_trademark(pools):
    """Pick a random trademark from the real data."""
    tm = random.choice(pools["trademarks"]["trademarks"])
    return tm


def get_body(item):
    """Extract body text from a content pool item (str or dict with 'body' key)."""
    if isinstance(item, dict):
        return item.get("body", str(item))
    return str(item)


def fill_template(template, replacements):
    """Fill placeholders in a template string."""
    result = get_body(template) if not isinstance(template, str) else template
    for key, val in replacements.items():
        result = result.replace(f"{{{key}}}", str(val))
    return result


def generate_all(output_dir, pools):
    """Generate all 7 documents and copy real PDFs."""
    manifest = {
        "generated_at": datetime.now().isoformat(),
        "documents": [],
    }

    firm = pools["names"]["firm"]
    ipd = pools["names"]["ipd"]
    content = pools["content_pools"]

    # ── 1. DOCX: Letter TO client ──────────────────────────────────
    client1 = pick_client(pools)
    tm1 = pick_trademark(pools)
    deadline1 = random_future_date(30, 120)
    body1 = random.choice(content["letter_to_client_bodies"])
    closing1 = random.choice(content["letter_closings"])

    replacements1 = {
        "deadline": deadline1,
        "tm_number": tm1["number"],
        "tm_text": tm1["text"],
        "client_name": client1["name"],
        "contact_person": client1["contact_person"],
    }

    client_dir = output_dir / "Client" / sanitize_dirname(client1["name"])
    client_dir.mkdir(parents=True, exist_ok=True)

    fname1 = f"Letter_Re_TM{tm1['number']}.docx"
    gen_letter_to(
        output_path=client_dir / fname1,
        firm=firm,
        client=client1,
        body=fill_template(body1, replacements1),
        closing=fill_template(closing1, replacements1),
        ref_number=f"JT/{datetime.now().year}/{random.randint(1000, 9999)}",
        date=datetime.now().strftime("%d %B %Y"),
        re_line=f"Trademark Application No. {tm1['number']} - {tm1['text']}",
    )

    manifest["documents"].append(
        {
            "filename": fname1,
            "path": f"Client/{sanitize_dirname(client1['name'])}/{fname1}",
            "type": "Letter to Client",
            "format": "docx",
            "expected_extraction": {
                "document_type": "Client Correspondence",
                "deadline": deadline1,
                "client": client1["name"],
                "tm_number": tm1["number"],
            },
        }
    )
    print(f"  [1/7] DOCX letter to client: {fname1}")

    # ── 2. PDF: Scanned letter FROM client ─────────────────────────
    client2 = pick_client(pools)
    tm2 = pick_trademark(pools)
    deadline2 = random_future_date(14, 90)
    body2 = random.choice(content["letter_from_client_bodies"])
    has_deadline2 = "{deadline}" in body2

    replacements2 = {
        "deadline": deadline2,
        "tm_number": tm2["number"],
        "tm_text": tm2["text"],
        "client_name": client2["name"],
        "contact_person": client2["contact_person"],
    }

    client2_dir = output_dir / "Client" / sanitize_dirname(client2["name"])
    client2_dir.mkdir(parents=True, exist_ok=True)

    fname2 = f"Client_Instructions_{sanitize_dirname(client2['name'])}.pdf"
    gen_scanned_letter(
        output_path=client2_dir / fname2,
        from_name=client2["contact_person"],
        from_company=client2["name"],
        from_address=client2["address"],
        to_name=firm["attorney"]["name"],
        to_firm=firm["name"],
        body=fill_template(body2, replacements2),
        date=datetime.now().strftime("%d %B %Y"),
    )

    manifest["documents"].append(
        {
            "filename": fname2,
            "path": f"Client/{sanitize_dirname(client2['name'])}/{fname2}",
            "type": "Letter from Client (Scanned)",
            "format": "pdf_scanned",
            "ocr_required": True,
            "expected_extraction": {
                "document_type": "Client Instructions",
                "deadline": deadline2 if has_deadline2 else None,
                "client": client2["name"],
                "tm_number": tm2["number"] if "{tm_number}" in body2 else None,
            },
        }
    )
    print(f"  [2/7] PDF scanned letter from client: {fname2}")

    # ── 3. PNG: Email FROM client ──────────────────────────────────
    client3 = pick_client(pools)
    tm3 = pick_trademark(pools)
    deadline3 = random_future_date(7, 60)
    email_body = random.choice(content["email_from_client_bodies"])
    email_subject = random.choice(content["email_subjects"])
    has_deadline3 = "{deadline}" in email_body

    replacements3 = {
        "deadline": deadline3,
        "tm_number": tm3["number"],
        "tm_text": tm3["text"],
        "client_name": client3["name"],
        "contact_person": client3["contact_person"],
    }

    client3_dir = output_dir / "Client" / sanitize_dirname(client3["name"])
    client3_dir.mkdir(parents=True, exist_ok=True)

    fname3 = f"Email_{sanitize_dirname(client3['name'])}_{datetime.now().strftime('%Y%m%d')}.png"
    gen_email_image(
        output_path=client3_dir / fname3,
        from_email=client3.get(
            "email", f"info@{client3['name'].lower().replace(' ', '')}.com"
        ),
        from_name=client3["contact_person"],
        to_email="benjamin.choi@jingtian.com",
        to_name=firm["attorney"]["name"],
        subject=fill_template(email_subject, replacements3),
        body=fill_template(email_body, replacements3),
        date=datetime.now().strftime("%A, %d %B %Y %H:%M"),
    )

    manifest["documents"].append(
        {
            "filename": fname3,
            "path": f"Client/{sanitize_dirname(client3['name'])}/{fname3}",
            "type": "Email from Client (Screenshot)",
            "format": "png",
            "ocr_required": True,
            "expected_extraction": {
                "document_type": "Client Email",
                "deadline": deadline3 if has_deadline3 else None,
                "client": client3["name"],
                "tm_number": tm3["number"]
                if "{tm_number}" in email_body or "{tm_number}" in email_subject
                else None,
            },
        }
    )
    print(f"  [3/7] PNG email screenshot: {fname3}")

    # ── 4. PDF: IPD Filing Receipt ─────────────────────────────────
    client4 = pick_client(pools)
    tm_number4 = random_tm_number()
    tm_text4 = random.choice(
        [
            client4["name"].split()[0].upper(),
            random.choice(["NOVA", "APEX", "STELLAR", "ZENITH", "PRIMEX", "VANTAGE"]),
        ]
    )
    filing_date = datetime.now().strftime("%d-%m-%Y")
    response_deadline4 = random_future_date(60, 120)
    nice_class = random.choice(list(pools["trademarks"]["nice_classes"].keys()))

    filing_dir = output_dir / "Admin" / "IPD e-filing"
    filing_dir.mkdir(parents=True, exist_ok=True)

    fname4 = f"Filing_Receipt_{tm_number4}.pdf"
    gen_filing_receipt(
        output_path=filing_dir / fname4,
        ipd=ipd,
        tm_number=tm_number4,
        tm_text=tm_text4,
        applicant=client4["name"],
        applicant_address=client4["address"],
        agent=firm["name"],
        agent_address=firm["address"],
        filing_date=filing_date,
        response_deadline=response_deadline4,
        nice_class=nice_class,
        class_description=pools["trademarks"]["nice_classes"][nice_class],
    )

    manifest["documents"].append(
        {
            "filename": fname4,
            "path": f"Admin/IPD e-filing/{fname4}",
            "type": "IPD Filing Receipt",
            "format": "pdf_native",
            "expected_extraction": {
                "document_type": "Filing Receipt",
                "deadline": response_deadline4,
                "client": client4["name"],
                "tm_number": tm_number4,
            },
        }
    )
    print(f"  [4/7] PDF filing receipt: {fname4}")

    # ── 5. DOCX: Internal Memo ─────────────────────────────────────
    memo_body = random.choice(content["memo_bodies"])
    clients_for_memo = random.sample(
        pools["clients"]["clients"], min(3, len(pools["clients"]["clients"]))
    )
    tms_for_memo = random.sample(
        pools["trademarks"]["trademarks"],
        min(3, len(pools["trademarks"]["trademarks"])),
    )

    memo_replacements = {}
    memo_deadlines = []
    nice_classes_list = list(pools["trademarks"]["nice_classes"].keys())
    for i in range(3):
        dl = random_future_date(14 + i * 30, 60 + i * 60)
        memo_deadlines.append(dl)
        memo_replacements[f"tm_number_{i + 1}"] = (
            tms_for_memo[i]["number"] if i < len(tms_for_memo) else random_tm_number()
        )
        # Use TM number as the mark reference (Chinese text causes rendering issues in memos)
        tm_text = tms_for_memo[i]["text"] if i < len(tms_for_memo) else "N/A"
        tm_num = (
            tms_for_memo[i]["number"] if i < len(tms_for_memo) else random_tm_number()
        )
        # If text is CJK, show as "No. XXXXXXX (text)", otherwise just the text
        memo_replacements[f"tm_text_{i + 1}"] = (
            tm_text if tm_text.isascii() else f"No. {tm_num}"
        )
        memo_replacements[f"deadline_{i + 1}"] = dl
        memo_replacements[f"client_{i + 1}"] = (
            clients_for_memo[i]["name"] if i < len(clients_for_memo) else "Various"
        )
        memo_replacements[f"class_{i + 1}"] = random.choice(nice_classes_list)
        memo_replacements[f"contact_person_{i + 1}"] = (
            clients_for_memo[i]["contact_person"]
            if i < len(clients_for_memo)
            else "N/A"
        )
    # Also fill generic placeholders
    memo_replacements["deadline"] = memo_deadlines[0]
    memo_replacements["contact_person"] = clients_for_memo[0]["contact_person"]
    memo_replacements["client_name"] = clients_for_memo[0]["name"]

    memo_dir = output_dir / "Admin" / "General Matter"
    memo_dir.mkdir(parents=True, exist_ok=True)

    fname5 = f"Memo_{datetime.now().strftime('%Y%m%d')}_{random.randint(100, 999)}.docx"
    gen_memo(
        output_path=memo_dir / fname5,
        firm=firm,
        body=fill_template(memo_body, memo_replacements),
        date=datetime.now().strftime("%d %B %Y"),
        subject="Upcoming Trademark Deadlines - Action Required",
    )

    manifest["documents"].append(
        {
            "filename": fname5,
            "path": f"Admin/General Matter/{fname5}",
            "type": "Internal Memo",
            "format": "docx",
            "expected_extraction": {
                "document_type": "Internal Memo",
                "deadlines": memo_deadlines,
                "tm_numbers": [
                    r.get(f"tm_number_{i + 1}")
                    for i, r in enumerate([memo_replacements] * 3)
                ],
            },
        }
    )
    print(f"  [5/7] DOCX internal memo: {fname5}")

    # ── 6. XLSX: Invoice Schedule ──────────────────────────────────
    invoice_clients = random.sample(
        pools["clients"]["clients"], min(6, len(pools["clients"]["clients"]))
    )
    invoice_tms = random.sample(
        pools["trademarks"]["trademarks"],
        min(6, len(pools["trademarks"]["trademarks"])),
    )
    invoice_descs = content["invoice_descriptions"]
    invoice_rows = []

    for i in range(min(6, len(invoice_clients))):
        cls = random.choice(list(pools["trademarks"]["nice_classes"].keys()))
        desc = fill_template(random.choice(invoice_descs), {"class": cls})
        due = random_future_date(14, 90)
        amount = random.randint(5, 150) * 1000
        invoice_rows.append(
            {
                "client": invoice_clients[i]["name"],
                "matter_ref": f"JT/{datetime.now().year}/{random.randint(1000, 9999)}",
                "tm_number": invoice_tms[i]["number"]
                if i < len(invoice_tms)
                else random_tm_number(),
                "description": desc,
                "amount_hkd": amount,
                "due_date": due,
                "status": random.choice(["Draft", "Sent", "Overdue", "Paid"]),
            }
        )

    billing_dir = output_dir / "Billing" / "Draft Bills"
    billing_dir.mkdir(parents=True, exist_ok=True)

    fname6 = f"Invoice_Schedule_{datetime.now().strftime('%Y')}Q{(datetime.now().month - 1) // 3 + 1}.xlsx"
    gen_invoice(
        output_path=billing_dir / fname6,
        rows=invoice_rows,
        firm=firm,
    )

    manifest["documents"].append(
        {
            "filename": fname6,
            "path": f"Billing/Draft Bills/{fname6}",
            "type": "Invoice Schedule",
            "format": "xlsx",
            "expected_extraction": {
                "document_type": "Invoice Schedule",
                "deadlines": [r["due_date"] for r in invoice_rows],
                "clients": [r["client"] for r in invoice_rows],
            },
        }
    )
    print(f"  [6/7] XLSX invoice schedule: {fname6}")

    # ── 7. PDF: TM Registry Record ─────────────────────────────────
    tm7 = pick_trademark(pools)
    client7 = pick_client(pools)
    status_type = random.choice(pools["trademarks"]["statuses"])
    # Some statuses imply deadlines
    has_implicit_deadline = status_type in [
        "Application Opposed",
        "Examined - First Examination Report Issued",
        "Examined - Further Examination Report Issued",
    ]

    ip_dir = output_dir / "IP"
    ip_dir.mkdir(parents=True, exist_ok=True)

    fname7 = f"TM_Record_{tm7['number']}.pdf"
    gen_tm_record(
        output_path=ip_dir / fname7,
        ipd=ipd,
        tm_number=tm7["number"],
        tm_text=tm7["text"],
        status=status_type,
        nice_class=str(tm7["classes"][0]) if tm7["classes"] else "5",
        class_description=pools["trademarks"]["nice_classes"].get(
            str(tm7["classes"][0]), "General goods and services"
        ),
        applicant=client7["name"],
        applicant_address=client7["address"],
        agent=firm["name"],
        agent_address=firm["address"],
        filing_date=tm7.get("filing_date", datetime.now().strftime("%d-%m-%Y")),
        publication_date=(
            datetime.now() - timedelta(days=random.randint(30, 180))
        ).strftime("%d-%m-%Y"),
    )

    manifest["documents"].append(
        {
            "filename": fname7,
            "path": f"IP/{fname7}",
            "type": "TM Registry Record",
            "format": "pdf_native",
            "expected_extraction": {
                "document_type": "Trademark Registry Record",
                "deadline": None,
                "deadline_note": "Implicit deadline based on status"
                if has_implicit_deadline
                else "No deadline",
                "client": client7["name"],
                "tm_number": tm7["number"],
                "status": status_type,
            },
        }
    )
    print(f"  [7/7] PDF TM registry record: {fname7}")

    # ── Copy real PDFs ─────────────────────────────────────────────
    if REAL_PDFS_DIR.exists():
        for pdf in REAL_PDFS_DIR.glob("*.pdf"):
            dest = ip_dir / pdf.name
            shutil.copy2(pdf, dest)
            manifest["documents"].append(
                {
                    "filename": pdf.name,
                    "path": f"IP/{pdf.name}",
                    "type": "Real Document (not generated)",
                    "format": "pdf",
                    "expected_extraction": None,
                }
            )
            print(f"  [+] Copied real PDF: {pdf.name}")

    # ── Save manifest ──────────────────────────────────────────────
    llm_dir = output_dir / "_LLM"
    llm_dir.mkdir(parents=True, exist_ok=True)
    manifest_path = llm_dir / "manifest.json"
    manifest_path.write_text(
        json.dumps(manifest, indent=2, ensure_ascii=False),
        encoding="utf-8",
    )
    print(f"\n  Manifest saved to {manifest_path}")

    return manifest


def main():
    parser = argparse.ArgumentParser(description="Generate JingTian sample documents")
    parser.add_argument(
        "--output",
        "-o",
        default=str(Path(__file__).parent / "outputs"),
        help="Output directory (default: ./outputs)",
    )
    parser.add_argument(
        "--seed", "-s", type=int, default=None, help="Random seed for reproducible runs"
    )
    args = parser.parse_args()

    if args.seed is not None:
        random.seed(args.seed)
        print(f"Using seed: {args.seed}")

    output_dir = Path(args.output)
    output_dir.mkdir(parents=True, exist_ok=True)

    print(f"Generating JingTian sample documents...")
    print(f"Output: {output_dir}\n")

    pools = load_pools()
    manifest = generate_all(output_dir, pools)

    print(f"\nDone! Generated {len(manifest['documents'])} documents.")


if __name__ == "__main__":
    main()
