"""
Inbound email webhook — called by Postfix pipe script.
Parses email, saves attachments, generates AI draft via Gemini,
creates IncomingEmail + Task records.
"""
import json
import os
import re
import base64
import logging
from datetime import datetime, timedelta

from google import genai
from google.genai import types as genai_types
from fastapi import APIRouter, Depends, HTTPException, Header, Request
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select

from app.config import settings
from app.database import get_db
from app.models.user import User
from app.models.task import Task
from app.models.incoming_email import IncomingEmail
from app.services.notifier import notify_admins, notify_user_group

logger = logging.getLogger(__name__)
router = APIRouter(prefix="/email", tags=["email"])

UPLOAD_DIR = os.path.join(os.path.dirname(__file__), "../../uploads/incoming")
os.makedirs(UPLOAD_DIR, exist_ok=True)


def _due_date():
    """Today before 4pm, tomorrow at or after 4pm."""
    now = datetime.now()
    if now.hour >= 16:
        return (now + timedelta(days=1)).date()
    return now.date()


def _extract_username(to_addr: str) -> str | None:
    """task-shella@jarvis.goteku.com → 'shella'"""
    match = re.search(r"task-([^@\s<>]+)@", to_addr, re.IGNORECASE)
    return match.group(1).lower() if match else None


def _save_attachment(filename: str, data_b64: str) -> str:
    """Decode base64 attachment, save to disk, return saved filename."""
    safe = re.sub(r"[^\w.\-]", "_", filename)
    path = os.path.join(UPLOAD_DIR, safe)
    base, ext = os.path.splitext(safe)
    counter = 1
    while os.path.exists(path):
        path = os.path.join(UPLOAD_DIR, f"{base}_{counter}{ext}")
        counter += 1
    with open(path, "wb") as f:
        f.write(base64.b64decode(data_b64))
    return os.path.basename(path)


def _generate_ai_draft(subject: str, body: str) -> str:
    """Call Gemini Flash to generate a formal Indonesian letter draft."""
    if not settings.GEMINI_API_KEY:
        return ""
    try:
        client = genai.Client(api_key=settings.GEMINI_API_KEY)
        prompt = (
            "Kamu adalah asisten surat bisnis formal Indonesia. "
            "Baca email masuk berikut dan buat draft balasan surat resmi dalam Bahasa Indonesia. "
            "Format: paragraf singkat, formal, profesional. Jangan sertakan header/footer surat. "
            "Hanya isi badan surat.\n\n"
            f"Subjek email: {subject}\n\n"
            f"Isi email:\n{body[:3000]}"
        )
        response = client.models.generate_content(
            model="gemini-2.5-flash",
            contents=prompt,
        )
        return response.text
    except Exception as e:
        logger.error(f"Gemini error: {e}")
        return ""


@router.post("/inbound", status_code=200)
async def email_inbound(
    request: Request,
    x_hook_secret: str = Header(default=""),
    db: AsyncSession = Depends(get_db),
):
    if x_hook_secret != settings.WEBHOOK_SECRET:
        raise HTTPException(403, "Invalid hook secret")

    payload = await request.json()

    subject         = payload.get("subject", "")
    from_addr       = payload.get("from", "")
    to_addr         = payload.get("to", "")
    body            = payload.get("body", "")
    attachments_raw = payload.get("attachments", [])

    username = _extract_username(to_addr)
    if not username:
        logger.warning(f"No task-username found in To: {to_addr}")
        return {"status": "ignored", "reason": "no task-username in To address"}

    result = await db.execute(select(User).where(User.username == username))
    user = result.scalar_one_or_none()
    if not user:
        logger.warning(f"User '{username}' not found")
        return {"status": "ignored", "reason": f"user '{username}' not found"}

    # Save attachments
    saved_files = []
    for att in attachments_raw:
        try:
            fname = _save_attachment(att["filename"], att["data"])
            saved_files.append(fname)
        except Exception as e:
            logger.error(f"Failed to save attachment {att.get('filename')}: {e}")

    # Generate AI draft (non-blocking — if fails, task still created)
    ai_draft = _generate_ai_draft(subject, body)

    # Create IncomingEmail
    incoming = IncomingEmail(
        subject=subject,
        from_email=from_addr,
        to_email=to_addr,
        body_raw=body,
        ai_draft=ai_draft,
        attachments=json.dumps(saved_files),
    )
    db.add(incoming)
    await db.flush()

    # Create Task
    task = Task(
        title=subject or f"Email from {from_addr}",
        status="todo",
        due_date=_due_date(),
        assigned_to=user.id,
        created_by=user.id,
    )
    db.add(task)
    await db.flush()

    incoming.task_id = task.id

    # Notify admins (in-app) + user group (Telegram)
    notif_title = f"Email masuk → Task baru: {task.title}"
    notif_body  = f"Dari: {from_addr}"
    notif_link  = f"/tasks/{task.id}"
    await notify_admins(db, notif_title, notif_body, notif_link)
    await notify_user_group(db, notif_title, notif_body, notif_link, thread_key="telegram_thread_task")

    await db.commit()

    logger.info(f"Created task #{task.id} for '{username}': {subject}")
    return {"status": "ok", "task_id": task.id, "incoming_email_id": incoming.id}
