# backend/app/plugins/contact_forms/services.py
from __future__ import annotations

import mimetypes
import os
import urllib.request

from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select

from app.services.email import send_email, render_tpl, TEMPLATE_META


async def get_form_with_fields(db: AsyncSession, form_id: int, tenant_id: int):
    """Load a ContactForm and attach its fields as form.fields list."""
    from app.core.models import ContactForm, ContactFormField
    r = await db.execute(
        select(ContactForm).where(
            ContactForm.id == form_id,
            ContactForm.tenant_id == tenant_id,
        )
    )
    form = r.scalar_one_or_none()
    if form is None:
        return None
    r2 = await db.execute(
        select(ContactFormField)
        .where(ContactFormField.form_id == form_id)
        .order_by(ContactFormField.sort_order, ContactFormField.id)
    )
    form.fields = list(r2.scalars().all())
    return form


def extract_submitter_info(data: dict, fields: list) -> tuple[str | None, str | None]:
    """Extract submitter email and name from submitted data based on field types."""
    email = None
    name = None
    email_field_names = {f.name for f in fields if f.field_type == "email"}
    name_field_names = {f.name for f in fields if f.field_type == "text" and "name" in f.name.lower()}
    for k, v in data.items():
        if k in email_field_names and not email:
            email = str(v)
        if k in name_field_names and not name:
            name = str(v)
    return email, name


async def _get_site_name(db: AsyncSession, tenant_id: int) -> str:
    """Get store name from tenant settings."""
    from app.core.models.tenant_settings import TenantSettings
    from sqlalchemy import select as sa_select
    r = await db.execute(
        sa_select(TenantSettings).where(TenantSettings.tenant_id == tenant_id)
    )
    settings_obj = r.scalar_one_or_none()
    return settings_obj.store_name if settings_obj and settings_obj.store_name else "LS"


def _normalize_url(v) -> str | None:
    """Extract URL string from either a plain string or a dict with 'url' key."""
    if not v:
        return None
    if isinstance(v, dict):
        return v.get("url") or None
    return str(v) or None


def _extract_file_urls(data: dict, fields: list) -> list[str]:
    """Collect all file URLs from file-type fields in the submission."""
    file_field_names = {f.name for f in fields if f.field_type == "file"}
    urls = []
    for name, value in data.items():
        if name not in file_field_names:
            continue
        if isinstance(value, list):
            for v in value:
                url = _normalize_url(v)
                if url:
                    urls.append(url)
        else:
            url = _normalize_url(value)
            if url:
                urls.append(url)
    return urls


def _fetch_file(url: str) -> tuple[str, bytes, str] | None:
    """Download or read a file and return (filename, bytes, mime_type). Returns None on failure."""
    _HERE = os.path.dirname(os.path.abspath(__file__))
    # services.py → contact_forms/ → plugins/ → app/ → backend/
    _BACKEND = os.path.abspath(os.path.join(_HERE, "../../../.."))
    _UPLOAD_DIR = os.path.join(_BACKEND, "static", "uploads")

    local_path = None
    for prefix in ("/api/static/uploads/", "/static/uploads/"):
        if url.startswith(prefix):
            local_path = os.path.join(_UPLOAD_DIR, url[len(prefix):])
            break

    try:
        if local_path and os.path.exists(local_path):
            with open(local_path, "rb") as f:
                content = f.read()
        elif url.startswith(("http://", "https://")):
            with urllib.request.urlopen(url, timeout=15) as resp:
                content = resp.read()
        else:
            return None

        filename = os.path.basename(url.split("?")[0]) or "attachment"
        mime_type, _ = mimetypes.guess_type(filename)
        return filename, content, mime_type or "application/octet-stream"
    except Exception as e:
        print(f"[ContactForm] Failed to fetch file {url}: {e}")
        return None


async def _collect_attachments(data: dict, fields: list) -> list:
    """Download all uploaded files and return as email attachment tuples."""
    attachments = []
    for url in _extract_file_urls(data, fields):
        result = _fetch_file(url)
        if result:
            attachments.append(result)
    return attachments


def _fields_table_html(data: dict, fields: list) -> str:
    """Render all submitted form fields as a clean HTML table, skipping file fields."""
    field_map = {f.name: f for f in fields}
    rows = []
    for f in fields:
        if f.field_type == "file":
            continue
        value = data.get(f.name)
        if value is None:
            continue
        display = ", ".join(str(x) for x in value) if isinstance(value, list) else str(value)
        bg = "#f9fafb" if len(rows) % 2 == 0 else "#ffffff"
        rows.append(
            f"<tr>"
            f"<td style='padding:8px 12px;border:1px solid #e5e7eb;background:{bg};font-weight:600;width:38%;'>{f.label}</td>"
            f"<td style='padding:8px 12px;border:1px solid #e5e7eb;background:{bg};'>{display}</td>"
            f"</tr>"
        )
    if not rows:
        return ""
    return (
        "<table style='width:100%;border-collapse:collapse;font-size:14px;margin:16px 0;'>"
        "<tbody>" + "".join(rows) + "</tbody></table>"
    )


def _label_to_key(label: str) -> str:
    """Convert 'First Name' → 'firstName' for friendly template variables."""
    import re
    words = re.split(r"[\s_\-]+", label.strip())
    if not words:
        return ""
    return words[0].lower() + "".join(w.capitalize() for w in words[1:])


async def send_form_emails(
    db: AsyncSession,
    form,
    submission,
    smtp_config: dict,
) -> None:
    """Send admin notification and optional visitor confirmation emails after form submission."""
    site_name = await _get_site_name(db, form.tenant_id)

    # 基础变量：以字段 name 为 key（auto-generated IDs）
    raw_vars = {
        k: (", ".join(str(x) for x in v) if isinstance(v, list) else str(v) if v is not None else "")
        for k, v in submission.data.items()
    }

    # 友好别名：以字段 label 的 camelCase 版本为 key（firstName, lastName 等）
    label_vars: dict = {}
    for f in form.fields:
        if f.field_type == "file":
            continue
        friendly_key = _label_to_key(f.label)
        if friendly_key and f.name in raw_vars:
            label_vars[friendly_key] = raw_vars[f.name]

    variables = {
        **raw_vars,
        **label_vars,
        "fields_table":    _fields_table_html(submission.data, form.fields),
        "form_title":      form.title or form.name,
        "submission_id":   str(submission.id),
        "submitter_name":  submission.submitter_name or "",
        "submitter_email": submission.submitter_email or "",
        "submitted_at":    submission.created_at.strftime("%Y-%m-%d %H:%M") if submission.created_at else "",
        "site_name":       site_name,
    }

    # 收集上传文件作为附件（仅 admin 通知邮件附带）
    attachments = await _collect_attachments(submission.data, form.fields)

    # Admin notification
    if form.notification_emails:
        meta = TEMPLATE_META["contact_form_notification"]
        subject = render_tpl(form.admin_email_subject or meta["default_subject"], variables)
        body = render_tpl(form.admin_email_body or meta["default_body"], variables)
        from app.tasks.email_tasks import send_email_task
        for email_addr in form.notification_emails:
            send_email_task.delay(
                to=email_addr, subject=subject, html_body=body,
                smtp_config=smtp_config,
            )

    # Visitor confirmation
    if form.confirm_email_enabled and submission.submitter_email:
        meta = TEMPLATE_META["contact_form_confirm"]
        subject = render_tpl(form.confirm_email_subject or meta["default_subject"], variables)
        body = render_tpl(form.confirm_email_body or meta["default_body"], variables)
        from app.tasks.email_tasks import send_email_task
        send_email_task.delay(
            to=submission.submitter_email,
            subject=subject,
            html_body=body,
            smtp_config=smtp_config,
        )


async def send_reply_email(
    db: AsyncSession,
    form,
    submission,
    reply_body: str,
    smtp_config: dict,
) -> None:
    """Send reply email to visitor when admin replies to a submission."""
    if not submission.submitter_email:
        return

    site_name = await _get_site_name(db, form.tenant_id)
    meta = TEMPLATE_META["contact_form_reply"]

    variables = {
        "form_title":    form.title or form.name,
        "submission_id": str(submission.id),
        "reply_body":    reply_body,
        "site_name":     site_name,
    }
    subject = render_tpl(meta["default_subject"], variables)
    body = render_tpl(meta["default_body"], variables)
    from app.tasks.email_tasks import send_email_task
    send_email_task.delay(
        to=submission.submitter_email,
        subject=subject,
        html_body=body,
        smtp_config=smtp_config,
    )
