from __future__ import annotations

import asyncio
import logging
import os
from datetime import datetime, timezone
from email.utils import parseaddr
from typing import Optional

from .email_notifications import _send_email
from . import slack_notifications

log = logging.getLogger(__name__)

_MAX_SNIPPET_CHARS = 240


def _parse_notification_emails(raw: str) -> list[str]:
    seen: set[str] = set()
    recipients: list[str] = []
    for token in (raw or "").split(","):
        candidate = token.strip()
        if not candidate:
            continue
        address = parseaddr(candidate)[1].strip().lower()
        if "@" not in address:
            continue
        if address in seen:
            continue
        seen.add(address)
        recipients.append(address)
    return recipients


def get_notification_recipients() -> list[str]:
    raw = (
        os.getenv("NOTIFY_EMAILS")
        or os.getenv("ADMIN_NOTIFY_EMAILS")
        or os.getenv("ALERT_TO_EMAILS")
        or ""
    )
    return _parse_notification_emails(raw)


def _trim(value: Optional[str], limit: int = _MAX_SNIPPET_CHARS) -> str:
    if not value:
        return ""
    compact = " ".join(value.strip().split())
    if len(compact) <= limit:
        return compact
    return f"{compact[: limit - 3]}..."


def _iso(value: Optional[datetime]) -> str:
    if value is None:
        return datetime.now(timezone.utc).isoformat()
    if value.tzinfo is None:
        return value.replace(tzinfo=timezone.utc).isoformat()
    return value.isoformat()


async def _fanout(subject: str, body: str) -> None:
    recipients = get_notification_recipients()
    if not recipients:
        log.debug("NOTIFY_EMAILS not configured; skipping admin alert: %s", subject)
        return

    results = await asyncio.gather(
        *[_send_email(to=recipient, subject=subject, body=body) for recipient in recipients],
        return_exceptions=True,
    )
    for recipient, result in zip(recipients, results):
        if isinstance(result, Exception):
            log.warning("Failed to send admin alert to %s: %s", recipient, result)


async def notify_beta_signup_received(
    *,
    email: str,
    name: str,
    domain: str,
    use_case: str,
    source: str,
    is_business_email: bool,
    ip_address: Optional[str],
    user_agent: Optional[str],
    submitted_at: Optional[datetime] = None,
) -> None:
    subject = f"[FoundryOps] New beta signup: {email}"
    body = "\n".join(
        [
            "New beta signup received.",
            "",
            f"Email: {email}",
            f"Name: {_trim(name, 120) or '-'}",
            f"Domain: {domain}",
            f"Business email: {'yes' if is_business_email else 'no'}",
            f"Source: {source or 'launch_site'}",
            f"Use case: {_trim(use_case) or '-'}",
            f"IP: {ip_address or '-'}",
            f"User-Agent: {_trim(user_agent, 180) or '-'}",
            f"Submitted at: {_iso(submitted_at)}",
        ]
    )
    await _fanout(subject, body)

    biz_tag = ":briefcase:" if is_business_email else ":envelope:"
    slack_text = (
        f":new: *New beta signup*\n"
        f"{biz_tag} *{email}* ({domain})\n"
        f"Name: {_trim(name, 120) or '-'} | Source: {source or 'launch_site'}\n"
        f"Use case: {_trim(use_case, 160) or '-'}"
    )
    await slack_notifications.notify_beta_channel(slack_text)


async def notify_support_ticket_created(
    *,
    public_id: str,
    account_id: Optional[str],
    user_email: str,
    ticket_type: Optional[str],
    category: Optional[str],
    severity: Optional[str],
    source: Optional[str],
    summary: str,
    description_snippet: Optional[str],
    created_at: Optional[datetime] = None,
) -> None:
    subject = f"[FoundryOps] New support ticket: {public_id}"
    body = "\n".join(
        [
            "New support ticket created.",
            "",
            f"Ticket ID: {public_id}",
            f"Account ID: {account_id or '-'}",
            f"User email: {user_email}",
            f"Type: {ticket_type or '-'}",
            f"Category: {category or '-'}",
            f"Severity: {severity or '-'}",
            f"Source: {source or '-'}",
            f"Summary: {_trim(summary, 180) or '-'}",
            f"Description: {_trim(description_snippet) or '-'}",
            f"Created at: {_iso(created_at)}",
        ]
    )
    await _fanout(subject, body)

    severity_emoji = {
        "critical": ":rotating_light:",
        "high": ":fire:",
        "medium": ":warning:",
        "low": ":information_source:",
    }.get((severity or "").lower(), ":ticket:")
    slack_text = (
        f"{severity_emoji} *New support ticket: {public_id}*\n"
        f"From: {user_email} | Type: {ticket_type or '-'} | Severity: {severity or '-'}\n"
        f"Summary: {_trim(summary, 180) or '-'}"
    )
    await slack_notifications.notify_support_channel(slack_text)


async def notify_support_inbound_email_received(
    *,
    from_email: Optional[str],
    to_email: Optional[str],
    subject_text: Optional[str],
    body_snippet: Optional[str],
    ticket_public_id: Optional[str],
    gmail_thread_id: Optional[str],
    gmail_message_id: Optional[str],
    received_at: Optional[datetime],
) -> None:
    matched_status = "matched" if ticket_public_id else "unmatched"
    subject = "[FoundryOps] Support email received"
    if ticket_public_id:
        subject = f"{subject}: {ticket_public_id}"

    body = "\n".join(
        [
            "Support mailbox inbound email received.",
            "",
            f"Status: {matched_status}",
            f"Ticket ID: {ticket_public_id or '-'}",
            f"From: {from_email or '-'}",
            f"To: {to_email or '-'}",
            f"Subject: {_trim(subject_text, 180) or '-'}",
            f"Snippet: {_trim(body_snippet) or '-'}",
            f"Gmail thread ID: {gmail_thread_id or '-'}",
            f"Gmail message ID: {gmail_message_id or '-'}",
            f"Received at: {_iso(received_at)}",
        ]
    )
    await _fanout(subject, body)

    status_emoji = ":link:" if ticket_public_id else ":question:"
    slack_text = (
        f"{status_emoji} *Support email received* ({matched_status})\n"
        f"From: {from_email or '-'} | Ticket: {ticket_public_id or 'unmatched'}\n"
        f"Subject: {_trim(subject_text, 120) or '-'}"
    )
    await slack_notifications.notify_support_channel(slack_text)


async def notify_sheet_webhook_delivery_failed(
    *,
    account_id: Optional[str],
    webhook_name: str,
    sheet_name: str,
    error_code: Optional[str],
    error_message: str,
    received_at: Optional[datetime] = None,
) -> None:
    subject = f"[FoundryOps] Sheet webhook failed: {webhook_name}"
    body = "\n".join(
        [
            "Sheet webhook delivery failed after ingest was accepted.",
            "",
            f"Account ID: {account_id or '-'}",
            f"Webhook: {webhook_name or '-'}",
            f"Target sheet: {sheet_name or '-'}",
            f"Error code: {error_code or '-'}",
            f"Error: {_trim(error_message) or '-'}",
            f"Received at: {_iso(received_at)}",
        ]
    )
    await _fanout(subject, body)

    slack_text = (
        f":warning: *Sheet webhook failed*\n"
        f"Webhook: {webhook_name or '-'} | Sheet: {sheet_name or '-'}\n"
        f"Account: {account_id or '-'} | Code: {error_code or '-'}\n"
        f"Error: {_trim(error_message, 160) or '-'}"
    )
    await slack_notifications.notify_support_channel(slack_text)
