# -*- coding: utf-8 -*-
"""Portable settings: proxy credentials + sync to proxy.env."""
from __future__ import annotations

import json
import os
import re
from pathlib import Path
from typing import Any


def proxy_home() -> Path:
    # Allow portable root override
    env = os.environ.get("CLAUDE_PROXY_HOME", "").strip()
    if env:
        return Path(env)
    return Path(os.environ["USERPROFILE"]) / ".claude-proxy-control"


def settings_path() -> Path:
    p = proxy_home() / "settings.json"
    p.parent.mkdir(parents=True, exist_ok=True)
    return p


def proxy_env_path() -> Path:
    return proxy_home() / "proxy.env"


DEFAULTS: dict[str, Any] = {
    "proxy_host": "",
    "proxy_port": "13128",
    "proxy_user": "proxy",
    "proxy_pass": "",
    "first_run_done": False,
    "auto_install_watcher": True,
    "auto_install_monitor": True,
    # Включать ли защиту сразу при запуске программы.
    #
    # Задумано было как «программа работает — трафик под контролем»: пока
    # sing-box не запущен, никто ничего не перехватывает. Но у окна есть и
    # другая работа — посмотреть каналы, раздать их программам, проверить
    # подписку, — и ради неё перестраивать весь сетевой стек и спрашивать
    # разрешение Windows незачем. Поэтому по умолчанию защиту включает человек,
    # кнопкой. Кому удобнее автоматически — ставит галочку в настройках.
    "autostart_tunnel": False,
    # --- tunnel hardening (escape hatches; defaults are the secure choice) ---
    # strict_route: without it an app that binds a specific interface walks past
    # the tunnel and route.final="block" never sees it.
    "strict_route": True,
    # tunnel_ipv6: without an inet6 address on the TUN, IPv6 traffic never enters
    # sing-box at all, so on an IPv6-enabled network "block" and "proxy" leak natively.
    "tunnel_ipv6": True,
    # secure_dns: plain UDP DNS hands every visited domain to the ISP regardless of
    # which channel the app is on. DoH keeps the query encrypted.
    "secure_dns": True,
    # Local Clash API - live introspection of what the running TUN actually does.
    "clash_api_port": 9095,
    "notes": "Sota VPN ставится отдельно пользователем",
}


def load_settings() -> dict[str, Any]:
    path = settings_path()
    data = dict(DEFAULTS)
    if path.is_file():
        try:
            raw = json.loads(path.read_text(encoding="utf-8"))
            if isinstance(raw, dict):
                data.update(raw)
        except Exception:
            pass
    # migrate from proxy.env if settings empty
    if not data.get("proxy_host"):
        migrated = read_proxy_env()
        if migrated.get("PROXY_HOST"):
            data["proxy_host"] = migrated.get("PROXY_HOST", "")
            data["proxy_port"] = migrated.get("PROXY_PORT", data["proxy_port"])
            data["proxy_user"] = migrated.get("PROXY_USER", data["proxy_user"])
            data["proxy_pass"] = migrated.get("PROXY_PASS", "")
    return data


def save_settings(data: dict[str, Any]) -> None:
    merged = dict(DEFAULTS)
    merged.update(data)
    settings_path().write_text(json.dumps(merged, ensure_ascii=False, indent=2), encoding="utf-8")
    sync_proxy_env(merged)


def read_proxy_env() -> dict[str, str]:
    path = proxy_env_path()
    out: dict[str, str] = {}
    if not path.is_file():
        return out
    for raw in path.read_text(encoding="utf-8").splitlines():
        line = raw.strip()
        if not line or line.startswith("#") or "=" not in line:
            continue
        k, v = line.split("=", 1)
        out[k.strip()] = v.strip()
    return out


def sync_proxy_env(settings: dict[str, Any] | None = None) -> None:
    """Write proxy.env used by Start-VpnClaude / builders / monitor."""
    s = settings if settings is not None else load_settings()
    host = str(s.get("proxy_host") or "").strip()
    port = str(s.get("proxy_port") or "13128").strip()
    user = str(s.get("proxy_user") or "").strip()
    password = str(s.get("proxy_pass") or "").strip()
    path = proxy_env_path()

    # Only the four keys anything actually reads. The old LOCAL_PROXY_* /
    # UPSTREAM_PROXY keys were written but never consumed, and UPSTREAM_PROXY
    # kept a second plaintext copy of the password in a full proxy URL.
    lines = [
        "# Generated by Claude Proxy Control settings — contains the proxy password.",
        "# Do not paste this file into chats, tickets or logs.",
        f"PROXY_HOST={host}",
        f"PROXY_PORT={port}",
        f"PROXY_USER={user}",
        f"PROXY_PASS={password}",
    ]
    path.write_text("\n".join(lines) + "\n", encoding="utf-8")


def settings_ready(settings: dict[str, Any] | None = None) -> bool:
    s = settings if settings is not None else load_settings()
    host = str(s.get("proxy_host") or "").strip()
    port = str(s.get("proxy_port") or "").strip()
    user = str(s.get("proxy_user") or "").strip()
    password = str(s.get("proxy_pass") or "").strip()
    if not host or not user or not password:
        return False
    if not re.fullmatch(r"\d{2,5}", port or ""):
        return False
    return True
