"""Campaigns: 12-step wizard (draft CRUD), preview with real rendered messages,
start/pause/resume/cancel, SSE live progress stream, per-recipient monitor, CSV export."""
import asyncio
import csv
import io
import json
import re
from typing import Optional

from fastapi import APIRouter, Depends, HTTPException, Query, Request
from fastapi.responses import StreamingResponse
from pydantic import BaseModel, Field
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, require_csrf
from app.core.config import settings as cfg
from app.core.security import log_audit
from app.models import (Attachment, Campaign, CampaignRecipient, CompanyPhoneNumber,
                        EmailTemplate, GmailAccount, Recipient, RecipientList,
                        SendJob, SubjectLine, SuppressionEntry, User)
from app.services.campaign_engine import get_setting, materialize_campaign
from app.services.campaign_service import (cancel_campaign, pause_campaign,
                                           resume_campaign, start_campaign)
from app.services.message_builder import sanitize_preview
from app.services.variable_engine import GeneratedValues, VariableEngine

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

MSG_TYPES = {"html", "plain", "both"}


class CampaignIn(BaseModel):
    name: str = Field(min_length=1, max_length=250)
    recipient_list_id: Optional[int] = None
    subject_set_ids: list = []
    template_ids: list = []
    message_type: str = "html"          # html|plain|both
    attach_mode: str = "none"           # none|pdf|file|image
    attach_pdf: bool = False
19:from app.models import (Attachment, Campaign, CampaignRecipient, CompanyPhoneNumber,
