from __future__ import annotations

import platform
import smtplib
import ssl
import subprocess
import urllib.parse
import webbrowser
from datetime import datetime
from email.message import EmailMessage

try:
    import keyring
except Exception:  # pragma: no cover
    keyring = None

from .models import CATEGORY_LABELS, Detection, Profile


KEYRING_SERVICE = "SafetyJudgeV13SMTP"


def format_report(profile: Profile, detections: list[Detection]) -> str:
    lines = [
        "Safety Judge V13 report",
        f"Profile: {profile.display_name}",
        f"Generated: {datetime.now().isoformat(timespec='seconds')}",
        "",
    ]
    for index, detection in enumerate(detections, start=1):
        label = CATEGORY_LABELS.get(detection.category, detection.category)
        lines.extend(
            [
                f"{index}. {label} — {detection.risk:.0%}",
                f"Text: {detection.text}",
                f"Reason: {detection.reason}",
                f"Source: {detection.source}",
                f"Application: {detection.app_hint or 'Unknown'}",
                f"Location: {detection.location_text}",
                f"Time: {detection.timestamp}",
                "",
            ]
        )
    return "\n".join(lines)


class ReportMailer:
    def keychain_available(self) -> bool:
        return keyring is not None

    def save_smtp_password(self, profile: Profile, password: str) -> None:
        if keyring is None:
            raise RuntimeError("System keychain support is unavailable.")
        sender = profile.smtp_sender.strip().lower()
        if not sender:
            raise RuntimeError("Set an SMTP sender email first.")
        keyring.set_password(KEYRING_SERVICE, f"{profile.profile_id}:{sender}", password)

    def has_smtp_password(self, profile: Profile) -> bool:
        if keyring is None or not profile.smtp_sender:
            return False
        try:
            return bool(
                keyring.get_password(
                    KEYRING_SERVICE,
                    f"{profile.profile_id}:{profile.smtp_sender.strip().lower()}",
                )
            )
        except Exception:
            return False

    def send_smtp(self, profile: Profile, detections: list[Detection]) -> None:
        if not profile.report_email:
            raise RuntimeError("This profile does not have a report email.")
        if keyring is None:
            raise RuntimeError("System keychain support is unavailable.")
        sender = profile.smtp_sender.strip().lower()
        password = keyring.get_password(KEYRING_SERVICE, f"{profile.profile_id}:{sender}")
        if not sender or not password:
            raise RuntimeError("SMTP sender or password is missing.")

        message = EmailMessage()
        message["From"] = sender
        message["To"] = profile.report_email
        message["Subject"] = f"Safety Judge alert — {datetime.now():%Y-%m-%d %H:%M}"
        message.set_content(format_report(profile, detections))

        context = ssl.create_default_context()
        with smtplib.SMTP(profile.smtp_server, profile.smtp_port, timeout=20) as smtp:
            smtp.starttls(context=context)
            smtp.login(sender, password)
            smtp.send_message(message)

    def open_draft(self, profile: Profile, detections: list[Detection]) -> None:
        if not profile.report_email:
            raise RuntimeError("Add a report email to this profile first.")
        subject = urllib.parse.quote(f"Safety Judge report — {datetime.now():%Y-%m-%d %H:%M}")
        body = urllib.parse.quote(format_report(profile, detections))
        webbrowser.open(
            f"mailto:{urllib.parse.quote(profile.report_email)}?subject={subject}&body={body}"
        )


def send_desktop_notification(title: str, message: str) -> None:
    system = platform.system()
    if system == "Darwin":
        safe_title = title.replace('"', "'")
        safe_message = message.replace('"', "'")
        script = f'display notification "{safe_message}" with title "{safe_title}"'
        try:
            subprocess.run(["osascript", "-e", script], timeout=3, capture_output=True)
        except Exception:
            pass
    elif system == "Linux":
        try:
            subprocess.run(["notify-send", title, message], timeout=3, capture_output=True)
        except Exception:
            pass
