"""Subject lines manager: CRUD, search, CSV/TXT import, export, clear-all."""
import csv
import io

from fastapi import APIRouter, Depends, File, HTTPException, UploadFile
from fastapi.responses import StreamingResponse
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_db
from app.core.config import settings
from app.models import SubjectLine, User

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


class SubjectIn(BaseModel):
    subject: str


@router.get("")
async def list_subjects(q: str = "", page: int = 1, limit: int = 100,
                        user: User = Depends(get_current_user), db: AsyncSession = Depends(get_db)):
    stmt = select(SubjectLine).where(SubjectLine.user_id == user.id)
    if q:
        stmt = stmt.where(SubjectLine.subject.ilike(f"%{q}%"))
    total = (await db.execute(select(func.count()).select_from(stmt.subquery()))).scalar()
    rows = (await db.execute(stmt.order_by(SubjectLine.id).offset((page - 1) * limit).limit(limit))).scalars().all()
    return {"total": total, "subjects": [{"id": s.id, "subject": s.subject,
                                          "use_count": s.use_count} for s in rows]}


@router.post("")
async def add_subject(payload: SubjectIn, user: User = Depends(get_current_user),
                      db: AsyncSession = Depends(get_db)):
    count = (await db.execute(select(func.count(SubjectLine.id)).where(
        SubjectLine.user_id == user.id))).scalar()
    if count >= settings.MAX_SUBJECTS:
        raise HTTPException(400, f"Maximum of {settings.MAX_SUBJECTS} subject variations reached")
    row = SubjectLine(user_id=user.id, subject=payload.subject.strip()[:500])
    db.add(row)
    await db.commit()
    return {"id": row.id, "subject": row.subject}


@router.post("/bulk")
async def add_bulk(payload: dict, user: User = Depends(get_current_user),
                   db: AsyncSession = Depends(get_db)):
    subjects = [s.strip() for s in (payload.get("subjects") or []) if s.strip()]
    if not subjects:
        raise HTTPException(400, "No subjects provided")
    count = (await db.execute(select(func.count(SubjectLine.id)).where(
        SubjectLine.user_id == user.id))).scalar()
    if count + len(subjects) > settings.MAX_SUBJECTS:
        raise HTTPException(400, f"Would exceed maximum of {settings.MAX_SUBJECTS} subjects")
    for s in subjects:
        db.add(SubjectLine(user_id=user.id, subject=s[:500]))
    await db.commit()
    return {"ok": True, "added": len(subjects)}


@router.post("/import")
async def import_subjects(file: UploadFile = File(...), user: User = Depends(get_current_user),
                          db: AsyncSession = Depends(get_db)):
    fname = (file.filename or "").lower()
    if fname.endswith(".json"):
        raise HTTPException(400, "Only CSV/TXT subject imports are supported")
    content = (await file.read()).decode("utf-8", errors="replace")
    subjects = []
=====TPL=====
"""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_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("")
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),
                          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),
                          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}


=====ATT=====
@router.get("/list")
async def list_attachments(kind: str = Query("", description="filter by kind"),
                           search: str = Query(""),
                           page: int = Query(1, ge=1),
                           page_size: int = Query(50, ge=1, le=200),
                           db: AsyncSession = Depends(get_db),
                           user: User = Depends(get_current_user)):
    q = select(Attachment).where(Attachment.user_id == user.id)
    if kind:
        q = q.where(Attachment.kind == kind)
    if search:
        q = q.where(Attachment.name.ilike(f"%{search}%"))
    total = (await db.execute(
        select(func.count()).select_from(q.subquery()))).scalar() or 0
    rows = (await db.execute(
        q.order_by(Attachment.id.desc()).offset((page - 1) * page_size).limit(page_size)
    )).scalars().all()
    return {"attachments": [_serialize(a) for a in rows],
            "total": total, "page": page, "page_size": page_size}


@router.post("/upload")
async def upload_attachment(file: UploadFile = File(...),
                            name: str = Query(""),
                            description: str = Query(""),
                            db: AsyncSession = Depends(get_db),
                            user: User = Depends(get_current_user),
                            _: None = Depends(require_csrf)):
    """Upload an attachment. Kind inferred from extension; stored with random prefix path.
    HTML files are stored as editable HTML attachments (variables substituted per recipient)."""
    content = await file.read()
    if len(content) > MAX_UPLOAD_BYTES:
        raise HTTPException(status_code=413, detail="File exceeds 10MB limit")
    if not content:
        raise HTTPException(status_code=400, detail="Empty file")

    orig = file.filename or "attachment.bin"
    ext = _ext(orig)
    kind = _kind_for(ext)
    if kind is None:
        raise HTTPException(status_code=400,
                            detail=f"Unsupported file type: {ext or 'unknown'}. Allowed: "
                                   f"txt, html, pdf, png, jpg, gif, webp, csv, zip")

    # security: scan buffer for executable magic before persisting
    verdict, reason = att_svc.scan_for_malware(content, orig)
    if not verdict:
        raise HTTPException(status_code=400, detail=f"Rejected by malware scan: {reason}")

    is_html = kind == "html"
    html_body = ""
    if is_html:
        try:
            html_body = content.decode("utf-8")
        except UnicodeDecodeError:
            raise HTTPException(status_code=400, detail="HTML file is not valid UTF-8")
        problems = validate_html(html_body)
        if problems.get("errors"):
            raise HTTPException(status_code=400,
                                detail=f"HTML rejected: {'; '.join(problems['errors'])}")
        # HTML attachments are stored inline (used with variable substitution at send time)
        att = Attachment(
            user_id=user.id,
            name=name or re.sub(r"\.[^.]+$", "", orig) or "html-attachment",
            filename=orig,
            stored_path="",
            mime_type="text/html",
            size_bytes=len(content),
            kind="html",
            description=description or "",
            is_html_attachment=True,
            html_attachment_body=html_body,
            file_sha256=hashlib.sha256(content).hexdigest(),
        )
    else:
        stored = att_svc.save_upload(orig, content)
        att = Attachment(
            user_id=user.id,
            name=name or re.sub(r"\.[^.]+$", "", orig) or "attachment",
            filename=orig,
            stored_path=stored["stored_path"],
            mime_type=MIME_BY_EXT.get(ext, "application/octet-stream"),
            size_bytes=len(content),
            kind=kind,
            description=description or "",
            file_sha256=hashlib.sha256(content).hexdigest(),
        )
    db.add(att)
    await db.commit()
    await log_audit(db, user.id, "attachment.upload", "attachment", att.id,
                    {"name": att.name, "kind": kind, "sha256": att.file_sha256,
                     "size": len(content)})
    return {"id": att.id, **_serialize(att)}


@router.post("/convert-pdf")
async def convert_html_to_pdf(template_id: int = Query(..., description="HTML template to render"),
                              db: AsyncSession = Depends(get_db),
                              user: User = Depends(get_current_user),
                              _: None = Depends(require_csrf)):
    """Convert one of the user's saved HTML templates into a real PDF attachment
    using WeasyPrint. The generated PDF is stored and can be attached to campaigns."""
    tpl = await db.get(EmailTemplate, template_id)
    if not tpl or tpl.user_id != user.id:
        raise HTTPException(status_code=404, detail="Template not found")

