
from __future__ import annotations

import json
import os
import smtplib
import sqlite3
import ssl
import time
import urllib.parse
import urllib.request
from email.message import EmailMessage
from hashlib import sha256
from pathlib import Path


def _root() -> Path:
    return Path(__file__).resolve().parent


def _db_path() -> Path:
    data_dir = os.environ.get("DATA_DIR", "").strip()
    return Path(data_dir) / "lev_state.db" if data_dir else _root() / "lev_state.db"


def _connect() -> sqlite3.Connection:
    con = sqlite3.connect(_db_path())
    con.execute(
        "CREATE TABLE IF NOT EXISTS lead_deliveries (lead_id TEXT NOT NULL, destination TEXT NOT NULL, status TEXT NOT NULL, payload_json TEXT, attempts INTEGER NOT NULL DEFAULT 0, last_error TEXT, created_at INTEGER NOT NULL, updated_at INTEGER NOT NULL, PRIMARY KEY (lead_id, destination))"
    )
    return con


def _lead_id(lead: dict) -> str:
    raw = "|".join(str(lead.get(key, "")) for key in ("dialog_id", "phone", "name", "consent_version"))
    return sha256(raw.encode("utf-8")).hexdigest()[:32]


def _destinations() -> list[str]:
    result = []
    if os.environ.get("PRIVACY_EMAIL_ENABLED", "").lower() == "true":
        result.append("email")
    if os.environ.get("PRIVACY_MAX_MANAGER_ENABLED", "").lower() == "true":
        result.append("max_manager")
    return result


def enqueue_lead(lead: dict) -> str:
    lead_id = lead.get("lead_id") or _lead_id(lead)
    payload = dict(lead)
    payload["lead_id"] = lead_id
    now = int(time.time())
    with _connect() as con:
        for destination in _destinations():
            con.execute(
                "INSERT OR IGNORE INTO lead_deliveries (lead_id, destination, status, payload_json, created_at, updated_at) VALUES (?, ?, 'pending', ?, ?, ?)",
                (lead_id, destination, json.dumps(payload, ensure_ascii=False), now, now),
            )
    retry_pending_deliveries()
    return lead_id


def _format_lead(lead: dict) -> str:
    lines = [
        "Новая заявка LEVBOT",
        f"Канал: {lead.get('channel', '')}",
        f"Диалог: {lead.get('dialog_id', '')}",
        f"Имя: {lead.get('name', '')}",
        f"Телефон: {lead.get('phone', '')}",
        f"Сообщение: {lead.get('message', '')}",
        f"Версия согласия: {lead.get('consent_version', '')}",
    ]
    return "\n".join(line for line in lines if not line.endswith(": "))


def deliver_to_email(lead: dict) -> None:
    host = os.environ.get("PRIVACY_SMTP_HOST", "").strip()
    port = int(os.environ.get("PRIVACY_SMTP_PORT", "465") or "465")
    username = os.environ.get("PRIVACY_SMTP_USERNAME", "").strip()
    password = os.environ.get("PRIVACY_SMTP_PASSWORD", "")
    from_email = os.environ.get("PRIVACY_SMTP_FROM", "").strip()
    to_email = os.environ.get("PRIVACY_LEAD_EMAIL_TO", "").strip()
    from_name = os.environ.get("PRIVACY_SMTP_FROM_NAME", "LEVBOT").strip() or "LEVBOT"
    if not host or not from_email or not to_email:
        raise RuntimeError("email delivery is not configured")
    msg = EmailMessage()
    msg["Subject"] = "Новая заявка LEVBOT"
    msg["From"] = f"{from_name} <{from_email}>"
    msg["To"] = to_email
    msg.set_content(_format_lead(lead))
    security = os.environ.get("PRIVACY_SMTP_SECURITY", "ssl").lower()
    if security == "starttls":
        with smtplib.SMTP(host, port, timeout=20) as smtp:
            smtp.starttls(context=ssl.create_default_context())
            if username:
                smtp.login(username, password)
            smtp.send_message(msg)
    else:
        with smtplib.SMTP_SSL(host, port, timeout=20, context=ssl.create_default_context()) as smtp:
            if username:
                smtp.login(username, password)
            smtp.send_message(msg)


def deliver_to_max(lead: dict) -> None:
    token = os.environ.get("MAX_ACCESS_TOKEN", "").strip()
    chat_id = os.environ.get("PRIVACY_MAX_MANAGER_CHAT_ID", "").strip()
    if not token or not chat_id:
        raise RuntimeError("MAX manager delivery is not configured")
    body = json.dumps({"text": _format_lead(lead)}, ensure_ascii=False).encode("utf-8")
    url = "https://botapi.max.ru/messages?" + urllib.parse.urlencode({"chat_id": chat_id})
    req = urllib.request.Request(url, data=body, method="POST", headers={"Authorization": f"Bearer {token}", "Content-Type": "application/json"})
    with urllib.request.urlopen(req, timeout=20) as response:
        if response.status >= 400:
            raise RuntimeError(f"MAX delivery HTTP {response.status}")


def retry_pending_deliveries(limit: int = 10) -> None:
    now = int(time.time())
    with _connect() as con:
        rows = con.execute("SELECT lead_id, destination, payload_json, attempts FROM lead_deliveries WHERE status='pending' ORDER BY created_at LIMIT ?", (limit,)).fetchall()
        for lead_id, destination, payload_json, attempts in rows:
            try:
                lead = json.loads(payload_json or "{}")
                if destination == "email":
                    deliver_to_email(lead)
                elif destination == "max_manager":
                    deliver_to_max(lead)
                con.execute("UPDATE lead_deliveries SET status='sent', payload_json='', updated_at=? WHERE lead_id=? AND destination=?", (now, lead_id, destination))
            except Exception as exc:
                con.execute("UPDATE lead_deliveries SET attempts=?, last_error=?, updated_at=? WHERE lead_id=? AND destination=?", (int(attempts or 0) + 1, str(exc)[:240], now, lead_id, destination))
