"""
E-Mail-Versand via SMTP (smtplib + asyncio.to_thread).
Konfiguration pro Firma in smtp_configs. Kein externer Mail-Dienst nötig.
"""
import asyncio
import smtplib
import ssl
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from typing import TYPE_CHECKING
from uuid import UUID

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

from app.core.config import settings
from app.models.smtp_config import SmtpConfig

if TYPE_CHECKING:
    from app.models.user import User


def _html_wrapper(title: str, body: str) -> str:
    return f"""
<!DOCTYPE html>
<html lang="de">
<head><meta charset="UTF-8"><title>{title}</title>
<style>
  body {{ font-family: system-ui, sans-serif; background: #f4f4f4; margin: 0; padding: 40px 20px; }}
  .card {{ background: white; border-radius: 12px; padding: 40px; max-width: 520px; margin: 0 auto; }}
  .logo {{ font-size: 22px; font-weight: 600; color: #2563EB; margin-bottom: 32px; }}
  h1 {{ font-size: 20px; font-weight: 600; color: #111; margin: 0 0 12px; }}
  p {{ font-size: 15px; color: #555; line-height: 1.6; margin: 0 0 16px; }}
  .btn {{ display: inline-block; padding: 12px 28px; background: #2563EB; color: white !important;
          text-decoration: none; border-radius: 8px; font-weight: 600; font-size: 15px; margin: 8px 0 24px; }}
  .footer {{ font-size: 12px; color: #999; margin-top: 32px; padding-top: 16px; border-top: 1px solid #eee; }}
</style></head>
<body><div class="card">
  <div class="logo">⏱ {settings.app_name}</div>
  {body}
  <div class="footer">Diese E-Mail wurde automatisch von {settings.app_name} gesendet.</div>
</div></body></html>
"""


def _decrypt_password(encrypted: str) -> str:
    """Fernet-Entschlüsselung über den zentralen Datenschlüssel (K-5)."""
    from app.core.crypto import decrypt_value
    return decrypt_value(encrypted)


def _smtp_send_sync(cfg: SmtpConfig, to: str, subject: str, html: str) -> None:
    """Synchroner SMTP-Versand – wird via asyncio.to_thread() aufgerufen."""
    password = _decrypt_password(cfg.password_encrypted) if cfg.password_encrypted else None

    msg = MIMEMultipart("alternative")
    msg["Subject"] = subject
    msg["From"] = f"{cfg.from_name} <{cfg.from_email}>"
    msg["To"] = to
    msg.attach(MIMEText(html, "html", "utf-8"))

    if cfg.use_tls:
        context = ssl.create_default_context()
        with smtplib.SMTP_SSL(cfg.host, cfg.port, context=context) as smtp:
            if cfg.username and password:
                smtp.login(cfg.username, password)
            smtp.send_message(msg)
    else:
        with smtplib.SMTP(cfg.host, cfg.port) as smtp:
            if cfg.use_starttls:
                smtp.starttls(context=ssl.create_default_context())
            if cfg.username and password:
                smtp.login(cfg.username, password)
            smtp.send_message(msg)


class EmailService:

    async def _load_smtp(self, company_id: UUID, db: AsyncSession) -> SmtpConfig | None:
        return await db.scalar(
            select(SmtpConfig).where(
                SmtpConfig.company_id == company_id,
                SmtpConfig.is_enabled == True,
            )
        )

    async def _send(self, to: str, subject: str, html: str, cfg: SmtpConfig | None) -> None:
        if not cfg:
            print(f"\n{'='*60}")
            print(f"EMAIL (kein SMTP konfiguriert – nicht versendet)")
            print(f"   To:      {to}")
            print(f"   Subject: {subject}")
            print(f"{'='*60}\n")
            return
        try:
            await asyncio.to_thread(_smtp_send_sync, cfg, to, subject, html)
        except Exception as exc:
            print(f"SMTP Fehler: {exc}")

    async def send_welcome(self, user: "User", db: AsyncSession) -> None:
        cfg = await self._load_smtp(user.company_id, db)
        body = f"""
        <h1>Willkommen bei {settings.app_name}, {user.first_name}!</h1>
        <p>Dein Firmen-Account wurde erfolgreich erstellt. Du kannst dich ab sofort anmelden.</p>
        <a href="{settings.frontend_url}/login" class="btn">Zum Login</a>
        """
        await self._send(user.email, f"Willkommen bei {settings.app_name}", _html_wrapper("Willkommen", body), cfg)

    async def send_invite(self, user: "User", invited_by: "User", raw_token: str, db: AsyncSession) -> None:
        cfg = await self._load_smtp(user.company_id, db)
        invite_url = f"{settings.frontend_url}/invite/accept#{raw_token}"
        body = f"""
        <h1>Du wurdest eingeladen!</h1>
        <p><strong>{invited_by.full_name}</strong> hat dich zu <strong>{settings.app_name}</strong> eingeladen.</p>
        <p>Klicke auf den Button, um dein Konto zu aktivieren und ein Passwort festzulegen.<br>
        Der Link ist <strong>7 Tage</strong> gültig.</p>
        <a href="{invite_url}" class="btn">Einladung annehmen</a>
        <p style="font-size:13px;color:#999;">Oder kopiere diesen Link: {invite_url}</p>
        """
        await self._send(
            user.email,
            f"{invited_by.full_name} hat dich zu {settings.app_name} eingeladen",
            _html_wrapper("Einladung", body),
            cfg,
        )

    async def send_password_reset(self, user: "User", raw_token: str, db: AsyncSession) -> None:
        cfg = await self._load_smtp(user.company_id, db)
        reset_url = f"{settings.frontend_url}/auth/reset-password#{raw_token}"
        body = f"""
        <h1>Passwort zurücksetzen</h1>
        <p>Hallo {user.first_name},</p>
        <p>du hast eine Anfrage zum Zurücksetzen deines Passworts gestellt.<br>
        Klicke auf den Button – der Link ist <strong>1 Stunde</strong> gültig.</p>
        <a href="{reset_url}" class="btn">Passwort zurücksetzen</a>
        <p>Falls du diese Anfrage nicht gestellt hast, kannst du diese E-Mail ignorieren.</p>
        """
        await self._send(user.email, "Passwort zurücksetzen", _html_wrapper("Passwort zurücksetzen", body), cfg)

    async def send_substitute_notification(
        self, substitute: "User", requester: "User", absence, db: AsyncSession
    ) -> None:
        """Informiert die eingetragene Vertretung über eine genehmigte Abwesenheit."""
        cfg = await self._load_smtp(substitute.company_id, db)
        start = absence.start_date.strftime("%d.%m.%Y")
        end = absence.end_date.strftime("%d.%m.%Y")
        zeitraum = start if start == end else f"{start} – {end}"
        body = f"""
        <h1>Du wurdest als Vertretung eingetragen</h1>
        <p>Hallo {substitute.first_name},</p>
        <p><strong>{requester.full_name}</strong> ist im Zeitraum <strong>{zeitraum}</strong>
        abwesend und hat dich als Vertretung benannt.</p>
        <a href="{settings.frontend_url}/absences" class="btn">Abwesenheiten ansehen</a>
        """
        await self._send(
            substitute.email,
            f"Vertretung für {requester.full_name} ({zeitraum})",
            _html_wrapper("Vertretung", body),
            cfg,
        )

    async def send_pending_approvals_digest(
        self, approver: "User", items: list[dict], db: AsyncSession
    ) -> None:
        """Tägliche Zusammenfassung offener Anträge an eine genehmigende Person."""
        cfg = await self._load_smtp(approver.company_id, db)
        rows = "".join(
            f"<li>{i['user_name']} – {i['type_name']} "
            f"({i['start']}{' – ' + i['end'] if i['end'] != i['start'] else ''}, "
            f"{i['working_days']} Tag(e))</li>"
            for i in items
        )
        body = f"""
        <h1>Offene Abwesenheitsanträge</h1>
        <p>Hallo {approver.first_name}, es warten <strong>{len(items)}</strong> Anträge auf deine Genehmigung:</p>
        <ul style="font-size:14px;color:#555;line-height:1.7">{rows}</ul>
        <a href="{settings.frontend_url}/absences?status=pending" class="btn">Anträge prüfen</a>
        """
        await self._send(
            approver.email, f"{len(items)} offene Abwesenheitsanträge",
            _html_wrapper("Offene Anträge", body), cfg,
        )

    async def send_carryover_expiry_reminder(
        self, user: "User", remaining: int, expires_at, db: AsyncSession
    ) -> None:
        cfg = await self._load_smtp(user.company_id, db)
        datum = expires_at.strftime("%d.%m.%Y")
        body = f"""
        <h1>Resturlaub verfällt bald</h1>
        <p>Hallo {user.first_name}, du hast noch <strong>{remaining} Urlaubstage</strong>,
        die am <strong>{datum}</strong> verfallen.</p>
        <p>Plane deinen Urlaub rechtzeitig ein, damit nichts verloren geht.</p>
        <a href="{settings.frontend_url}/absences" class="btn">Urlaub planen</a>
        """
        await self._send(
            user.email, f"Dein Resturlaub verfällt am {datum}",
            _html_wrapper("Resturlaub", body), cfg,
        )

    async def send_certificate_overdue_digest(
        self, hr_user: "User", items: list[dict], db: AsyncSession
    ) -> None:
        cfg = await self._load_smtp(hr_user.company_id, db)
        rows = "".join(
            f"<li>{i['user_name']} – krank seit {i['start']}, AU fällig seit {i['due']}</li>"
            for i in items
        )
        body = f"""
        <h1>Fehlende AU-Bescheinigungen</h1>
        <p>Hallo {hr_user.first_name}, für <strong>{len(items)}</strong> Krankmeldung(en)
        fehlt die Arbeitsunfähigkeitsbescheinigung:</p>
        <ul style="font-size:14px;color:#555;line-height:1.7">{rows}</ul>
        <a href="{settings.frontend_url}/absences" class="btn">Abwesenheiten ansehen</a>
        """
        await self._send(
            hr_user.email, f"{len(items)} fehlende AU-Bescheinigung(en)",
            _html_wrapper("AU fehlt", body), cfg,
        )

    async def send_test(self, cfg: SmtpConfig, to: str) -> None:
        """Test-E-Mail direkt mit übergebenem Konfigurationsobjekt."""
        body = f"""
        <h1>SMTP-Test erfolgreich!</h1>
        <p>Deine SMTP-Konfiguration für <strong>{settings.app_name}</strong> funktioniert korrekt.</p>
        <p>Server: {cfg.host}:{cfg.port}</p>
        """
        await self._send(to, f"{settings.app_name} – SMTP-Test", _html_wrapper("SMTP-Test", body), cfg)


email_service = EmailService()
