"""HTML templates manager: paste/upload/editor/preview/duplicate/import/clear-all."""
import re
import secrets

from fastapi import APIRouter, Depends, File, Form, HTTPException, UploadFile
from fastapi.responses import HTMLResponse
from pydantic import BaseModel
from sqlalchemy import delete as sa_delete, func, select
from sqlalchemy.ext.asyncio import AsyncSession

from app.api.deps import get_current_user, get_current_user_csrf, get_db
from app.core.config import settings
from app.models import EmailTemplate, User
from app.services import message_builder
from app.services.variable_engine import analyze_template_variables

router = APIRouter(prefix="/templates", tags=["templates"])


class TemplateIn(BaseModel):
    name: str
    body_html: str
    body_text: str = ""
    subject_hint: str = ""


@router.get("/list")
async def list_templates(user: User = Depends(get_current_user), db: AsyncSession = Depends(get_db)):
    rows = (await db.execute(select(EmailTemplate).where(EmailTemplate.user_id == user.id)
                             .order_by(EmailTemplate.id))).scalars().all()
    out = []
    for t in rows:
        analysis = analyze_template_variables(t.body_html)
        out.append({"id": t.id, "name": t.name, "subject_hint": t.subject_hint,
                    "source": t.source, "sequence_order": t.sequence_order,
                    "size_html": len(t.body_html), "variables": analysis["variables"],
                    "unknown_variables": analysis["unknown"],
                    "created_at": t.created_at.isoformat()})
    return {"templates": out, "count": len(out)}


@router.post("")
async def create_template(payload: TemplateIn, user: User = Depends(get_current_user_csrf),
                          db: AsyncSession = Depends(get_db)):
    if not payload.body_html.strip():
        raise HTTPException(400, "HTML body is required")
    if len(payload.body_html) > 1024 * 1024:
        raise HTTPException(413, "Template too large (max 1 MB)")
    problems = []
    if re.search(r"<script", payload.body_html, re.I):
        problems.append("Script tags are not allowed")
    if problems:
        raise HTTPException(400, problems)
    row = EmailTemplate(user_id=user.id, name=payload.name[:250], body_html=payload.body_html,
                        body_text=payload.body_text, subject_hint=payload.subject_hint[:500],
                        source="paste")
    db.add(row)
    await db.commit()
    return {"id": row.id, "name": row.name}


@router.post("/upload")
async def upload_template(file: UploadFile = File(...), name: str = Form(""),
                          user: User = Depends(get_current_user_csrf),
                          db: AsyncSession = Depends(get_db)):
    fname = (file.filename or "").lower()
    if not fname.endswith((".html", ".htm", ".txt")):
        raise HTTPException(400, "Only .html/.htm/.txt template files are accepted")
    content = (await file.read()).decode("utf-8", errors="replace")
    if len(content) > 1024 * 1024:
        raise HTTPException(413, "Template too large")
    if re.search(r"<script", content, re.I):
        raise HTTPException(400, "Script tags are not allowed")
    row = EmailTemplate(user_id=user.id, name=(name or file.filename)[:250], body_html=content,
                        source="upload")
    db.add(row)
    await db.commit()
    return {"id": row.id, "name": row.name}


@router.post("/upload-multiple")
async def upload_multiple(files: list[UploadFile] = File(...),
                          user: User = Depends(get_current_user_csrf),
                          db: AsyncSession = Depends(get_db)):
    created = []
    for f in files:
        fname = (f.filename or "").lower()
        if not fname.endswith((".html", ".htm", ".txt")):
            continue
        content = (await f.read()).decode("utf-8", errors="replace")
        if len(content) > 1024 * 1024 or re.search(r"<script", content, re.I):
            continue
        row = EmailTemplate(user_id=user.id, name=f.filename[:250], body_html=content,
                            source="upload")
        db.add(row)
        created.append(f.filename)
    await db.commit()
    return {"ok": True, "created": created, "count": len(created)}


@router.get("/{template_id}")
async def get_template(template_id: int, user: User = Depends(get_current_user),
                       db: AsyncSession = Depends(get_db)):
    t = await db.get(EmailTemplate, template_id)
    if not t or t.user_id != user.id:
        raise HTTPException(404, "Not found")
    analysis = analyze_template_variables(t.body_html)
    return {"id": t.id, "name": t.name, "subject_hint": t.subject_hint,
            "body_html": t.body_html, "body_text": t.body_text,
            "variables": analysis["variables"], "unknown_variables": analysis["unknown"]}


@router.put("/{template_id}")
async def edit_template(template_id: int, payload: TemplateIn,
                        user: User = Depends(get_current_user_csrf), db: AsyncSession = Depends(get_db)):
    t = await db.get(EmailTemplate, template_id)
    if not t or t.user_id != user.id:
        raise HTTPException(404, "Not found")
    if re.search(r"<script", payload.body_html, re.I):
        raise HTTPException(400, "Script tags are not allowed")
    t.name = payload.name[:250]
    t.body_html = payload.body_html
    t.body_text = payload.body_text
    t.subject_hint = payload.subject_hint[:500]
    await db.commit()
    return {"ok": True}


@router.post("/{template_id}/duplicate")
async def duplicate_template(template_id: int, user: User = Depends(get_current_user_csrf),
                             db: AsyncSession = Depends(get_db)):
    t = await db.get(EmailTemplate, template_id)
    if not t or t.user_id != user.id:
        raise HTTPException(404, "Not found")
    row = EmailTemplate(user_id=user.id, name=f"{t.name} (copy)", body_html=t.body_html,
                        body_text=t.body_text, subject_hint=t.subject_hint, source=t.source)
    db.add(row)
    await db.commit()
    return {"id": row.id}


@router.delete("/{template_id}")
async def delete_template(template_id: int, user: User = Depends(get_current_user_csrf),
                          db: AsyncSession = Depends(get_db)):
    t = await db.get(EmailTemplate, template_id)
    if not t or t.user_id != user.id:
        raise HTTPException(404, "Not found")
    await db.delete(t)
    await db.commit()
    return {"ok": True}


@router.post("/clear-all")
async def clear_all(user: User = Depends(get_current_user_csrf), db: AsyncSession = Depends(get_db)):
    result = await db.execute(sa_delete(EmailTemplate).where(EmailTemplate.user_id == user.id))
    await db.commit()
    return {"deleted": result.rowcount or 0}


@router.post("/{template_id}/preview")
async def preview_template(template_id: int, sample: dict = {},
                           user: User = Depends(get_current_user_csrf),
                           db: AsyncSession = Depends(get_db)):
    """Render template with sample data (sanitized) and run validation."""
    t = await db.get(EmailTemplate, template_id)
    if not t or t.user_id != user.id:
        raise HTTPException(404, "Not found")
    from app.services.variable_engine import GeneratedValues, VariableEngine
    engine = VariableEngine(sample.get("config", {}))
    g = GeneratedValues(
        invoice_number=engine.generate_invoice_number(set()),
        amount=engine.generate_amount(), shipping=engine.generate_shipping(),
        random_name=engine.generate_random_name(),
        invoice_date=sample.get("invoice_date", "2026-01-15"),
        due_date=sample.get("due_date", "2026-01-30"),
        phone=sample.get("phone", "+1 555 000 0000"),
    )
    res = engine.substitute(t.body_html, sample.get("recipient", {
        "FirstName": "John", "LastName": "Smith", "CompanyName": "Example Corp",
        "CustomerEmail": "customer@example.com", "Email": "john@example.com"}),
        g, custom_fields=sample.get("custom_fields", {}),
        extra={"unsubscribe_link": "https://example.com/unsubscribe?token=sample"})
    problems = message_builder.validate_html(res.text)
    return {"rendered_html": message_builder.sanitize_preview(res.text),
            "unknown_variables": res.unknown, "missing_variables": res.missing,
            "warnings": problems,
            "generated": {"invoice_number": g.invoice_number, "amount": g.amount,
                          "shipping": g.shipping}}


@router.post("/{template_id}/test-pdf")
async def test_pdf(template_id: int, sample: dict = {},
                   user: User = Depends(get_current_user_csrf), db: AsyncSession = Depends(get_db)):
    """Real HTML->PDF conversion test; returns the PDF inline."""
    t = await db.get(EmailTemplate, template_id)
    if not t or t.user_id != user.id:
        raise HTTPException(404, "Not found")
    from app.services.variable_engine import GeneratedValues, VariableEngine
    engine = VariableEngine(sample.get("config", {}))
    g = GeneratedValues(invoice_number=engine.generate_invoice_number(set()),
                        amount=engine.generate_amount(), shipping=engine.generate_shipping(),
                        invoice_date=sample.get("invoice_date", "2026-01-15"),
                        due_date=sample.get("due_date", "2026-01-30"))
    res = engine.substitute(t.body_html, sample.get("recipient", {}), g,
                            extra={"unsubscribe_link": "https://example.com/unsubscribe"})
    pdf = message_builder.html_to_pdf(res.text)
    import base64
    return {"pdf_base64": base64.b64encode(pdf).decode(), "size_bytes": len(pdf),
            "engine": "WeasyPrint"}


@router.post("/{template_id}/test-image")
async def test_image(template_id: int, sample: dict = {},
                     user: User = Depends(get_current_user_csrf), db: AsyncSession = Depends(get_db)):
    """Real HTML→PNG conversion test; returns the image inline."""
    t = await db.get(EmailTemplate, template_id)
    if not t or t.user_id != user.id:
        raise HTTPException(404, "Not found")
    from app.services.variable_engine import GeneratedValues, VariableEngine
    engine = VariableEngine(sample.get("config", {}))
    g = GeneratedValues(invoice_number=engine.generate_invoice_number(set()),
                        amount=engine.generate_amount(), shipping=engine.generate_shipping(),
                        invoice_date=sample.get("invoice_date", "2026-01-15"),
                        due_date=sample.get("due_date", "2026-01-30"))
    res = engine.substitute(t.body_html, sample.get("recipient", {}), g,
                            extra={"unsubscribe_link": "https://example.com/unsubscribe"})
    png = message_builder.html_to_image(res.text)
    import base64
    return {"png_base64": base64.b64encode(png).decode(), "size_bytes": len(png),
            "engine": "wkhtmltoimage"}


@router.post("/{template_id}/test-word")
async def test_word(template_id: int, sample: dict = {},
                    user: User = Depends(get_current_user_csrf), db: AsyncSession = Depends(get_db)):
    """Real HTML→Word (.docx) conversion test; returns the document inline."""
    t = await db.get(EmailTemplate, template_id)
    if not t or t.user_id != user.id:
        raise HTTPException(404, "Not found")
    from app.services.variable_engine import GeneratedValues, VariableEngine
    engine = VariableEngine(sample.get("config", {}))
    g = GeneratedValues(invoice_number=engine.generate_invoice_number(set()),
                        amount=engine.generate_amount(), shipping=engine.generate_shipping(),
                        invoice_date=sample.get("invoice_date", "2026-01-15"),
                        due_date=sample.get("due_date", "2026-01-30"))
    res = engine.substitute(t.body_html, sample.get("recipient", {}), g,
                            extra={"unsubscribe_link": "https://example.com/unsubscribe"})
    docx = message_builder.html_to_docx(res.text)
    import base64
    return {"docx_base64": base64.b64encode(docx).decode(), "size_bytes": len(docx),
            "engine": "python-docx"}
