
from __future__ import annotations

import html
import json
import os
import re
import sqlite3
import time
from pathlib import Path

from fastapi.responses import HTMLResponse

from lead_delivery import enqueue_lead


ACCEPT_PHRASES = {"согласен", "согласна", "да, согласен", "да, согласна", "подтверждаю согласие"}
DECLINE_PHRASES = {"не согласен", "не согласна", "отказываюсь", "не даю согласие"}
PHONE_RE = re.compile(r"(?:(?:\+7|8)[\s\-()]*)?\d[\d\s\-()]{8,}\d")


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


def _load_config() -> dict:
    path = _root() / os.environ.get("PRIVACY_CONFIG_PATH", "privacy.json")
    if not path.is_file():
        return {"enabled": False}
    try:
        data = json.loads(path.read_text(encoding="utf-8"))
        return data if isinstance(data, dict) else {"enabled": False}
    except Exception:
        return {"enabled": False}


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 privacy_consents (dialog_id TEXT PRIMARY KEY, status TEXT NOT NULL, phone TEXT, message TEXT, consent_version TEXT, created_at INTEGER NOT NULL, updated_at INTEGER NOT NULL)"
    )
    return con


def _route_html(rel_path: str) -> HTMLResponse:
    path = (_root() / rel_path).resolve()
    root = _root().resolve()
    if root not in path.parents and path != root:
        return HTMLResponse("Not found", status_code=404)
    if not path.is_file():
        return HTMLResponse("Not found", status_code=404)
    return HTMLResponse(path.read_text(encoding="utf-8"), media_type="text/html; charset=utf-8")


def _dialog_id(chat_id, client_id) -> str:
    return str(client_id or chat_id or "site")


def _status(dialog_id: str) -> tuple[str, str, str]:
    with _connect() as con:
        row = con.execute("SELECT status, phone, message FROM privacy_consents WHERE dialog_id=?", (dialog_id,)).fetchone()
    if not row:
        return ("none", "", "")
    return (str(row[0] or ""), str(row[1] or ""), str(row[2] or ""))


def _save_status(dialog_id: str, status: str, phone: str = "", message: str = "", version: str = "") -> None:
    now = int(time.time())
    with _connect() as con:
        con.execute(
            "INSERT INTO privacy_consents (dialog_id, status, phone, message, consent_version, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?) ON CONFLICT(dialog_id) DO UPDATE SET status=excluded.status, phone=COALESCE(NULLIF(excluded.phone,''), privacy_consents.phone), message=COALESCE(NULLIF(excluded.message,''), privacy_consents.message), consent_version=COALESCE(NULLIF(excluded.consent_version,''), privacy_consents.consent_version), updated_at=excluded.updated_at",
            (dialog_id, status, phone, message, version, now, now),
        )


def _phone(text: str) -> str:
    match = PHONE_RE.search(str(text or ""))
    return match.group(0).strip() if match else ""


def _consent_prompt(cfg: dict) -> str:
    docs = cfg.get("documents") if isinstance(cfg.get("documents"), dict) else {}
    privacy = docs.get("privacy_url") or docs.get("privacy_path") or "/legal/privacy"
    consent = docs.get("consent_url") or docs.get("consent_path") or "/legal/consent"
    return (
        "Перед тем как принять контакт и передать заявку, нужно согласие на обработку персональных данных.\n\n"
        f"Политика: {privacy}\n"
        f"Согласие: {consent}\n\n"
        "Если согласны, ответьте: Согласен"
    )


def _lead_payload(cfg: dict, dialog_id: str, phone: str, message: str) -> dict:
    docs = cfg.get("documents") if isinstance(cfg.get("documents"), dict) else {}
    return {
        "dialog_id": dialog_id,
        "channel": "site",
        "phone": phone,
        "message": message,
        "consent_version": docs.get("version", ""),
    }


def install(server_module):
    app = server_module.app
    original_turn = server_module.turn

    @app.get("/legal/privacy")
    async def levbot_privacy_policy():
        return _route_html(os.environ.get("PRIVACY_POLICY_PATH", "legal/privacy.html"))

    @app.get("/legal/consent")
    async def levbot_privacy_consent():
        return _route_html(os.environ.get("PRIVACY_CONSENT_PATH", "legal/consent.html"))

    async def turn_with_privacy(chat_id, user_text, image_data_uri="", client_id=""):
        cfg = _load_config()
        if not cfg.get("enabled") or not (cfg.get("consent") or {}).get("required_before_contact_collection"):
            return await original_turn(chat_id, user_text, image_data_uri, client_id)
        dialog_id = _dialog_id(chat_id, client_id)
        text = str(user_text or "").strip()
        normalized = text.lower().replace("ё", "е")
        status, pending_phone, pending_message = _status(dialog_id)
        if normalized in ACCEPT_PHRASES:
            _save_status(dialog_id, "accepted", version=(cfg.get("documents") or {}).get("version", ""))
            phone = pending_phone or _phone(pending_message)
            if phone:
                enqueue_lead(_lead_payload(cfg, dialog_id, phone, pending_message or text))
                return "Спасибо, согласие принято. Заявка передана менеджеру."
            return "Спасибо, согласие принято. Напишите, пожалуйста, контакт для связи."
        if normalized in DECLINE_PHRASES:
            _save_status(dialog_id, "declined")
            return "Понял. Без согласия я не буду передавать контактные данные менеджеру."
        phone = _phone(text)
        if phone and status != "accepted":
            _save_status(dialog_id, "pending", phone=phone, message=text, version=(cfg.get("documents") or {}).get("version", ""))
            return _consent_prompt(cfg)
        return await original_turn(chat_id, user_text, image_data_uri, client_id)

    server_module.turn = turn_with_privacy
    return app
