#!/usr/bin/env python3
import hashlib
import json
import os
import sqlite3
from pathlib import Path

DB_PATH = "/etc/x-ui/x-ui.db"
BASE_DIR = Path("/root/clash-sub")
SUBS_DIR = BASE_DIR / "subs"
BASE_URL = os.environ.get("CLASH_SUB_BASE_URL", "https://sub.mrhear.xyz")
NODE_HOST = os.environ.get("CLASH_NODE_HOST", "vps.mrhear.xyz")


def deterministic_token(client_id: str) -> str:
    return hashlib.sha256(client_id.encode("utf-8")).hexdigest()[:24]


def load_vless_reality_inbound():
    conn = sqlite3.connect(DB_PATH)
    cur = conn.cursor()
    cur.execute(
        "select id,port,settings,stream_settings from inbounds "
        "where protocol='vless' and enable=1 order by id desc limit 1"
    )
    row = cur.fetchone()
    conn.close()
    if not row:
        raise RuntimeError("No enabled VLESS inbound found.")
    inbound_id, port, settings_raw, stream_raw = row
    settings = json.loads(settings_raw)
    stream = json.loads(stream_raw)
    return inbound_id, port, settings, stream


def render_yaml(name, uuid, port, sni, fp, pbk, sid, flow):
    flow_line = f"    flow: {flow}\n" if flow else ""
    return f"""mixed-port: 7890
allow-lan: false
mode: rule
log-level: info
ipv6: true

proxies:
  - name: "{name}"
    type: vless
    server: {NODE_HOST}
    port: {port}
    uuid: {uuid}
    network: tcp
    udp: true
    tls: true
    servername: {sni}
    client-fingerprint: {fp}
{flow_line}    reality-opts:
      public-key: {pbk}
      short-id: {sid}

proxy-groups:
  - name: "PROXY"
    type: select
    proxies:
      - "{name}"
      - DIRECT

rules:
  - MATCH,PROXY
"""


def main():
    SUBS_DIR.mkdir(parents=True, exist_ok=True)
    inbound_id, port, settings, stream = load_vless_reality_inbound()

    clients = settings.get("clients", [])
    if not clients:
        raise RuntimeError("No clients found in inbound settings.")

    reality = stream.get("realitySettings", {})
    reality_cfg = reality.get("settings", {})
    sni = (reality.get("serverNames") or ["www.apple.com"])[0]
    sid = (reality.get("shortIds") or ["d8"])[0]
    fp = reality_cfg.get("fingerprint", "chrome")
    pbk = reality_cfg.get("publicKey")
    if not pbk:
        raise RuntimeError("Reality public key not found in inbound stream settings.")

    generated_files = set()
    links = []

    for client in clients:
        client_id = client.get("id")
        if not client_id:
            continue
        email = client.get("email") or f"client-{client_id[:8]}"
        flow = client.get("flow") or ""
        token = deterministic_token(client_id)
        filename = f"{token}.yaml"
        yaml_text = render_yaml(email, client_id, port, sni, fp, pbk, sid, flow)
        (SUBS_DIR / filename).write_text(yaml_text, encoding="utf-8")
        generated_files.add(filename)
        links.append(
            {
                "name": email,
                "uuid": client_id,
                "url": f"{BASE_URL}/subs/{filename}",
            }
        )

    for old in SUBS_DIR.glob("*.yaml"):
        if old.name not in generated_files:
            old.unlink(missing_ok=True)

    links.sort(key=lambda x: x["name"].lower())
    index_lines = [
        "<!doctype html>",
        "<html><head><meta charset='utf-8'><title>Clash Subscriptions</title></head>",
        "<body><h2>Clash Subscription Links</h2>",
        f"<p>Inbound ID: {inbound_id}</p>",
        "<ul>",
    ]
    for item in links:
        index_lines.append(
            f"<li><b>{item['name']}</b> - "
            f"<a href=\"{item['url']}\">{item['url']}</a></li>"
        )
    index_lines.extend(["</ul>", "</body></html>"])
    (SUBS_DIR / "index.html").write_text("\n".join(index_lines), encoding="utf-8")
    (SUBS_DIR / "index.txt").write_text(
        "\n".join([f"{x['name']} {x['url']}" for x in links]) + "\n",
        encoding="utf-8",
    )

    if links:
        first_url = links[0]["url"]
        (BASE_DIR / "sub.yaml").write_text((SUBS_DIR / f"{deterministic_token(links[0]['uuid'])}.yaml").read_text(encoding="utf-8"), encoding="utf-8")
        print(f"Generated {len(links)} client subscriptions.")
        print(f"Index: {BASE_URL}/subs/index.html")
        print(f"First client: {first_url}")
    else:
        print("No links generated.")


if __name__ == "__main__":
    main()
