@router.get("/list")
async def list_campaigns(status: str = Query(""),
                         search: str = Query(""),
                         page: int = Query(1, ge=1),
                         page_size: int = Query(20, ge=1, le=100),
                         db: AsyncSession = Depends(get_db),
                         user: User = Depends(get_current_user)):
    q = select(Campaign).where(Campaign.user_id == user.id)
    if status:
        q = q.where(Campaign.status == status)
    if search:
        q = q.where(Campaign.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(Campaign.id.desc())
                             .offset((page - 1) * page_size).limit(page_size))).scalars().all()
    return {"campaigns": [_ser(c) for c in rows], "total": total,
            "page": page, "page_size": page_size}


@router.post("/create")
async def create_campaign(payload: CampaignIn, db: AsyncSession = Depends(get_db),
                          user: User = Depends(get_current_user),
                          _: None = Depends(require_csrf)):
    """Create a new campaign (wizard step 12 / Save). Validates all references."""
    errors = await _validate_refs(db, user, payload)
    if errors:
        raise HTTPException(status_code=400, detail={"message": "Validation failed",
                                                     "errors": errors})
    c = Campaign(user_id=user.id, **payload.model_dump())
    db.add(c)
    await db.commit()
    await log_audit(db, user.id, "campaign.create", "campaign", c.id, {"name": c.name})
    return _ser(c)


@router.get("/{cid}")
async def get_campaign(cid: int, user: User = Depends(get_current_user),
                       db: AsyncSession = Depends(get_db)):
    return _ser(await _get_own(db, user, cid))


@router.post("/{cid}/patch")
async def patch_campaign(cid: int, payload: CampaignIn,
                         db: AsyncSession = Depends(get_db),
                         user: User = Depends(get_current_user),
                         _: None = Depends(require_csrf)):
    """Full update (wizard edit). Only allowed while draft/paused/queued."""
    c = await _get_own(db, user, cid)
    if c.status not in ("draft", "paused", "queued", "failed"):
        raise HTTPException(status_code=409,
                            detail=f"Cannot edit a {c.status} campaign")
    errors = await _validate_refs(db, user, payload)
    if errors:
        raise HTTPException(status_code=400, detail={"message": "Validation failed",
                                                     "errors": errors})
    data = payload.model_dump()
    for k, v in data.items():
        setattr(c, k, v)
    await db.commit()
    await log_audit(db, user.id, "campaign.patch", "campaign", c.id, {"fields": list(data.keys())})
    return _ser(c)


@router.post("/{cid}/delete")
async def delete_campaign(cid: int, db: AsyncSession = Depends(get_db),
                          user: User = Depends(get_current_user),
                          _: None = Depends(require_csrf)):
    c = await _get_own(db, user, cid)
    if c.status == "running":
        raise HTTPException(status_code=409, detail="Pause or cancel the campaign first")
    await db.delete(c)
    await db.commit()
    await log_audit(db, user.id, "campaign.delete", "campaign", cid, {"name": c.name})
    return {"deleted": cid}


@router.post("/clear-all")
async def clear_all_campaigns(db: AsyncSession = Depends(get_db),
                              user: User = Depends(get_current_user),
                              _: None = Depends(require_csrf)):
    """Delete ALL campaigns (not running ones). Requires explicit UI confirmation."""
    rows = (await db.execute(select(Campaign).where(Campaign.user_id == user.id))).scalars().all()
    deleted, skipped = 0, 0
    for c in rows:
        if c.status == "running":
            skipped += 1
            continue
        await db.delete(c)
        deleted += 1
    await db.commit()
    await log_audit(db, user.id, "campaign.clear_all", "campaign", None,
                    {"deleted": deleted, "skipped": skipped})
    return {"deleted": deleted, "skipped": skipped}


# ---------------------------------------------------------------------------
# Preview: materialize the campaign plan and render REAL messages (no sending)
# ---------------------------------------------------------------------------

@router.post("/{cid}/preview")
async def preview_campaign(cid: int, sample_size: int = Query(0),
                           db: AsyncSession = Depends(get_db),
                           user: User = Depends(get_current_user),
                           _: None = Depends(require_csrf)):
    """Preview: generate the campaign plan for a sample of recipients and render
    the actual messages (subject + HTML + substituted variables). NOTHING is sent."""
    c = await _get_own(db, user, cid)
    if c.status not in ("draft", "paused", "queued", "failed"):
        raise HTTPException(status_code=409, detail="Cannot preview a running campaign")

    size = sample_size or c.preview_sample_size or 5
    size = max(1, min(size, 20))

    if not c.recipient_list_id:
        raise HTTPException(status_code=400, detail="Campaign has no recipient list")
