"""Public unsubscribe endpoints: tokenized link from sent emails (/unsubscribe/{token}).
Adds the email to the suppression list, records an EmailEvent, and never exposes
any account data. No authentication required (token IS the credential)."""
from datetime import datetime, timezone

from fastapi import APIRouter, Depends, HTTPException, Request
from fastapi.responses import HTMLResponse
from pydantic import BaseModel
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession

from app.api.deps import get_db, rate_limit_user
from app.db.session import AsyncSessionLocal
from app.models import Campaign, CampaignRecipient, EmailEvent, Recipient, RecipientList, SuppressionEntry

router = APIRouter(tags=["unsubscribe"])

UNSUB_PAGE = """<!DOCTYPE html>
<html lang="en"><head><meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Unsubscribe — {title}</title>
<style>
  body {{ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
         background: #f4f5f7; display: flex; justify-content: center; min-height: 100vh;
         margin: 0; align-items: center; }}
  .card {{ background: #fff; border-radius: 12px; box-shadow: 0 4px 16px rgba(0,0,0,.08);
          padding: 40px; max-width: 460px; width: 90%; text-align: center; }}
  h1 {{ font-size: 22px; color: #1a1d21; margin: 0 0 12px; }}
  p {{ color: #555; font-size: 15px; line-height: 1.6; margin: 0 0 24px; }}
  .ok {{ color: #0e7a3d; font-size: 40px; }}
  .err {{ color: #c0392b; font-size: 40px; }}
  .email {{ font-weight: 600; color: #1a1d21; word-break: break-all; }}
</style></head>
<body><div class="card">{icon}<h1>{heading}</h1><p>{message}</p>
</div></body></html>"""


def _page(icon: str, heading: str, message: str) -> HTMLResponse:
    html = UNSUB_PAGE.format(title=heading, icon=icon, heading=heading, message=message)
    return HTMLResponse(html, status_code=200)


@router.get("/unsubscribe/{token}", response_class=HTMLResponse)
async def unsubscribe_page(token: str, db: AsyncSession = Depends(get_db)):
    """Public unsubscribe landing page. Shows confirmation form (one-click safe)."""
    if len(token) < 20 or len(token) > 64:
        return _page("❌", "Invalid link",
                     "This unsubscribe link is invalid or malformed.")
    rec = (await db.execute(
        select(Recipient).where(Recipient.unsub_token == token))).scalar()
    if not rec:
        return _page("❌", "Invalid link",
                     "We could not find this unsubscribe link. It may have expired "
                     "or the recipient list was removed.")
    email = rec.email
    already = (await db.execute(
        select(SuppressionEntry).where(SuppressionEntry.email == email))).scalar()
    if already:
        return _page("✅", "Already unsubscribed",
                     f'<span class="email">{email}</span> is already on our '
                     'do-not-contact list. You will not receive further emails.')
    return _page("📮", "Unsubscribe",
                 f'Do you want to stop receiving emails at '
                 f'<span class="email">{email}</span>? Press the button to confirm. '
                 f'<form method="post" action="/unsubscribe/{token}">'
                 f'<button type="submit" style="background:#c0392b;color:#fff;border:0;'
                 f'padding:12px 28px;border-radius:8px;font-size:15px;cursor:pointer;">'
                 f'Confirm unsubscribe</button></form>')


@router.post("/unsubscribe/{token}", response_class=HTMLResponse)
async def unsubscribe_confirm(token: str, db: AsyncSession = Depends(get_db)):
    """Confirm unsubscribe: add to suppression list + record event. Idempotent."""
    if len(token) < 20 or len(token) > 64:
        return _page("❌", "Invalid link", "This unsubscribe link is invalid.")
    rec = (await db.execute(
        select(Recipient).where(Recipient.unsub_token == token))).scalar()
    if not rec:
        return _page("❌", "Invalid link",
                     "We could not find this unsubscribe link.")

    email = rec.email
    existing = (await db.execute(
        select(SuppressionEntry).where(SuppressionEntry.email == email))).scalar()
    if not existing:
        # resolve the list owner explicitly (lazy-loading rec.list is forbidden
        # inside an async session — it raised MissingGreenlet and 500'd the flow)
        rl_user = None
        if rec.list_id:
            rl_user = (await db.execute(
                select(RecipientList.user_id).where(RecipientList.id == rec.list_id)
            )).scalar()
        db.add(SuppressionEntry(user_id=rl_user,
                                email=email, reason="unsubscribed",
                                source="unsubscribe-link"))
        await db.commit()

    # record event on the most recent campaign_recipient for this email (if any)
    cr = (await db.execute(
        select(CampaignRecipient).where(CampaignRecipient.email == email)
        .order_by(CampaignRecipient.id.desc()).limit(1))).scalar()
    if cr:
        db.add(EmailEvent(campaign_id=cr.campaign_id,
                          campaign_recipient_id=cr.id,
                          event_type="unsubscribed",
                          detail=f"Unsubscribed via token link from {email}"))
        rec.status = "unsubscribed"
        await db.commit()

    return _page("✅", "Unsubscribed",
                 f'<span class="email">{email}</span> has been added to our '
                 'do-not-contact list. You will not receive further emails from us. '
                 'This took effect immediately.')


@router.get("/unsubscribe-status/{token}")
async def unsubscribe_status(token: str, db: AsyncSession = Depends(get_db)):
    """JSON status endpoint (used by List-Unsubscribe-Post one-click handlers)."""
    rec = (await db.execute(
        select(Recipient).where(Recipient.unsub_token == token))).scalar()
    if not rec:
        return {"subscribed": False, "error": "invalid token"}
    suppressed = (await db.execute(
        select(SuppressionEntry).where(SuppressionEntry.email == rec.email))).scalar()
    return {"subscribed": not bool(suppressed), "email_domain": rec.email.split("@")[-1]}
