"""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_current_user_csrf, 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("/list")
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_csrf),
                      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")
    subject = payload.subject.strip()[:500]
    if not subject:
        raise HTTPException(400, "Subject line cannot be empty")
    row = SubjectLine(user_id=user.id, subject=subject)
    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_csrf),
                   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_csrf),
                          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 = []
    if fname.endswith(".csv"):
        for row in csv.reader(io.StringIO(content)):
            first = row[0].strip() if row else ""
            if first and first.lower() not in ("subject", "subject line"):
                subjects.append(first)
    else:
        for line in content.splitlines():
            line = line.strip()
            if line and not line.startswith("#") and line.lower() != "subject":
                subjects.append(line)
    subjects = subjects[:settings.MAX_SUBJECTS]
    existing = set((await db.execute(select(SubjectLine.subject).where(
        SubjectLine.user_id == user.id))).scalars().all())
    added = 0
    for s in subjects:
        if s not in existing:
            db.add(SubjectLine(user_id=user.id, subject=s[:500]))
            added += 1
    await db.commit()
    return {"ok": True, "seen": len(subjects), "added": added}


@router.get("/export")
async def export_subjects(user: User = Depends(get_current_user), db: AsyncSession = Depends(get_db)):
    rows = (await db.execute(select(SubjectLine).where(SubjectLine.user_id == user.id)
                             .order_by(SubjectLine.id))).scalars().all()
    buf = io.StringIO()
    w = csv.writer(buf)
    w.writerow(["subject", "use_count"])
    for s in rows:
        w.writerow([s.subject, s.use_count])
    buf.seek(0)
    return StreamingResponse(iter([buf.getvalue()]), media_type="text/csv",
                             headers={"Content-Disposition": "attachment; filename=subjects.csv"})


@router.put("/{subject_id}")
async def edit_subject(subject_id: int, payload: SubjectIn,
                       user: User = Depends(get_current_user_csrf), db: AsyncSession = Depends(get_db)):
    row = await db.get(SubjectLine, subject_id)
    if not row or row.user_id != user.id:
        raise HTTPException(404, "Not found")
    row.subject = payload.subject.strip()[:500]
    await db.commit()
    return {"ok": True}


@router.delete("/{subject_id}")
async def delete_subject(subject_id: int, user: User = Depends(get_current_user_csrf),
                         db: AsyncSession = Depends(get_db)):
    row = await db.get(SubjectLine, subject_id)
    if not row or row.user_id != user.id:
        raise HTTPException(404, "Not found")
    await db.delete(row)
    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(SubjectLine).where(SubjectLine.user_id == user.id))
    await db.commit()
    return {"deleted": result.rowcount or 0}
