# -*- coding: utf-8 -*-
from __future__ import annotations

import os
import sys
import webbrowser
from typing import Any, Callable
from urllib.parse import quote

from PySide6.QtWidgets import (
    QApplication,
    QFormLayout,
    QGroupBox,
    QHBoxLayout,
    QLabel,
    QLineEdit,
    QMainWindow,
    QMessageBox,
    QPushButton,
    QTabWidget,
    QTextEdit,
    QVBoxLayout,
    QWidget,
)

import config as cfg
from bsphp_client import APIResult, BSPHPClient, ClientConfig, InitFailedError
from machine_code import get_machine_code
from ui_common import INPUT_FIELD_QSS, run_async


def renew_url_for_user(user: str) -> str:
    u = user.strip()
    if not u:
        return cfg.CARD_RENEW_URL_BASE
    return f"{cfg.CARD_RENEW_URL_BASE}&user={quote(u)}"


class CardControlPanel(QMainWindow):
    def __init__(self, parent: "CardDemoQt", client: BSPHPClient, logged_id: str, vip_exp: str) -> None:
        super().__init__(parent)
        self.parent_ref = parent
        self.client = client
        self.logged_id = logged_id
        self.setWindowTitle("主控制面板")
        self.resize(920, 640)
        root = QWidget(self)
        self.setCentralWidget(root)
        layout = QVBoxLayout(root)
        layout.addWidget(QLabel(f"当前卡号：{logged_id}"))
        self.vip_label = QLabel(f"到期时间：{vip_exp}")
        layout.addWidget(self.vip_label)
        self.aux_pwd = QLineEdit()
        self.aux_pwd.setPlaceholderText("可选：卡密码")
        self.aux_pwd.setEchoMode(QLineEdit.Password)
        self.detail = QTextEdit()
        self.detail.setReadOnly(True)
        layout.addWidget(self._section("常用接口", [
            ("刷新到期", self._refresh_exp),
            ("登录状态", lambda: self._run("登录状态", self.client.get_login_info)),
            ("心跳", lambda: self._run("心跳", self.client.heartbeat)),
            ("公告", lambda: self._run("公告", self.client.get_notice)),
            ("服务器时间", lambda: self._run("服务器时间", self.client.get_server_date)),
            ("版本", lambda: self._run("版本", self.client.get_version)),
            ("软件描述", lambda: self._run("软件描述", self.client.get_soft_info)),
        ]))
        layout.addWidget(self._section("配置接口", [
            ("预设URL", lambda: self._run("预设URL", self.client.get_preset_url)),
            ("Web地址", lambda: self._run("Web地址", self.client.get_web_url)),
            ("全局配置", lambda: self._run("全局配置", self.client.get_global_info)),
            ("逻辑A", lambda: self._run("逻辑A", self.client.get_logic_a)),
            ("逻辑B", lambda: self._run("逻辑B", self.client.get_logic_b)),
            ("软件配置", lambda: self._run("软件配置", lambda: self.client.get_app_custom("myapp"))),
            ("VIP配置", lambda: self._run("VIP配置", lambda: self.client.get_app_custom("myvip"))),
            ("登录配置", lambda: self._run("登录配置", lambda: self.client.get_app_custom("mylogin"))),
        ]))
        ops = QHBoxLayout()
        b1 = QPushButton("绑定本机")
        b1.clicked.connect(lambda: self._run("绑定本机", lambda: self.client.bind_card(self.client.machine_code, self.logged_id, self.aux_pwd.text().strip())))
        b2 = QPushButton("解除绑定")
        b2.clicked.connect(lambda: self._run("解除绑定", lambda: self.client.unbind_card(self.logged_id, self.aux_pwd.text().strip())))
        b3 = QPushButton("激活查询")
        b3.clicked.connect(lambda: self._run("激活查询", lambda: self.client.query_card(self.logged_id)))
        b4 = QPushButton("卡信息示例")
        b4.clicked.connect(lambda: self._run("卡信息示例", lambda: self.client.get_card_info(self.logged_id, self.aux_pwd.text().strip(), "UserName", None)))
        for b in (b1, b2, b3, b4):
            ops.addWidget(b)
        ops.addStretch(1)
        w = QWidget(); w.setLayout(ops); layout.addWidget(w)
        web_ops = QHBoxLayout()
        wb1 = QPushButton("续费充值")
        wb1.clicked.connect(lambda: webbrowser.open(renew_url_for_user(self.logged_id)))
        wb2 = QPushButton("购买充值卡")
        wb2.clicked.connect(lambda: webbrowser.open(cfg.CARD_GEN_URL))
        wb3 = QPushButton("购买库存卡")
        wb3.clicked.connect(lambda: webbrowser.open(cfg.CARD_STOCK_URL))
        wb4 = QPushButton("注销并返回登录")
        wb4.clicked.connect(self._logout)
        for b in (wb1, wb2, wb3, wb4):
            web_ops.addWidget(b)
        web_ops.addStretch(1)
        ww = QWidget(); ww.setLayout(web_ops); layout.addWidget(ww)
        layout.addWidget(QLabel("卡密（解绑、绑定本机、卡信息等需要时填写）"))
        layout.addWidget(self.aux_pwd)
        layout.addWidget(self.detail, 1)

    def _section(self, title: str, actions: list[tuple[str, Callable[[], None]]]) -> QWidget:
        box = QGroupBox(title)
        lay = QHBoxLayout(box)
        for text, fn in actions:
            b = QPushButton(text)
            b.clicked.connect(fn)
            lay.addWidget(b)
        lay.addStretch(1)
        return box

    def _run(self, title: str, fn: Callable[[], APIResult]) -> None:
        def done(res: Any) -> None:
            if isinstance(res, Exception):
                QMessageBox.critical(self, "错误", repr(res))
                return
            self.detail.setPlainText(f"[{title}] code={res.code}\n{res.message() or '（无 data 文本）'}")
        run_async(fn, done)

    def _refresh_exp(self) -> None:
        def done(res: Any) -> None:
            if isinstance(res, Exception):
                return
            t = res.message()
            if t:
                self.vip_label.setText(f"到期时间：{t}")
        run_async(self.client.get_date_ic, done)

    def _logout(self) -> None:
        def done(_: Any) -> None:
            self.parent_ref.logged_id = ""
            self.close()
        run_async(self.client.logout, done)


class CardDemoQt(QMainWindow):
    def __init__(self) -> None:
        super().__init__()
        self.setWindowTitle("BSPHP 卡模式演示 (PySide6)")
        self.resize(920, 700)
        self.client = BSPHPClient(
            ClientConfig(
                url=cfg.BSPHP_URL,
                mutual_key=cfg.BSPHP_MUTUAL_KEY,
                server_private_key=cfg.BSPHP_SERVER_PRIVATE_KEY,
                client_public_key=cfg.BSPHP_CLIENT_PUBLIC_KEY,
            ),
            get_machine_code,
        )
        self.ready = False
        self.logged_id = ""
        self.panel: CardControlPanel | None = None
        self._init_ui()
        self.bootstrap()

    def _init_ui(self) -> None:
        root = QWidget(self)
        self.setCentralWidget(root)
        layout = QVBoxLayout(root)
        self.notice = QTextEdit(); self.notice.setReadOnly(True); self.notice.setFixedHeight(90)
        layout.addWidget(self.notice)
        st = QHBoxLayout()
        self.status_dot = QLabel("●")
        self.status_txt = QLabel("未连接")
        retry = QPushButton("重新连接"); retry.clicked.connect(self.bootstrap)
        st.addWidget(self.status_dot); st.addWidget(self.status_txt); st.addStretch(1); st.addWidget(retry)
        layout.addLayout(st)
        self.tabs = QTabWidget()
        layout.addWidget(self.tabs, 1)
        self._build_card_tab()
        self._build_machine_tab()
        self.status_line = QLabel("待操作")
        layout.addWidget(self.status_line)

    def _build_card_tab(self) -> None:
        page = QWidget(); f = QFormLayout(page)
        self.card_id = QLineEdit(); self.card_pwd = QLineEdit()
        self.card_pwd.setEchoMode(QLineEdit.Password)
        self.card_pwd.setPlaceholderText("没有密码请留空")
        f.addRow("卡串", self.card_id); f.addRow("密码", self.card_pwd)
        row = QHBoxLayout()
        actions = [
            ("验证使用", self.verify_card),
            ("网络测试", self.test_net),
            ("版本检测", self.check_version),
            ("续费充值", lambda: webbrowser.open(renew_url_for_user(self.card_id.text()))),
            ("购买充值卡", lambda: webbrowser.open(cfg.CARD_GEN_URL)),
            ("购买库存卡", lambda: webbrowser.open(cfg.CARD_STOCK_URL)),
        ]
        for t, fn in actions:
            b = QPushButton(t); b.clicked.connect(fn); row.addWidget(b)
        row.addStretch(1)
        w = QWidget(); w.setLayout(row)
        f.addRow("", w)
        self.tabs.addTab(page, "制作卡密登陆模式")

    def _build_machine_tab(self) -> None:
        page = QWidget()
        outer = QVBoxLayout(page)
        sub = QTabWidget()
        outer.addWidget(sub)
        p1 = QWidget(); f1 = QFormLayout(p1)
        self.machine_verify_id = QLineEdit(get_machine_code())
        f1.addRow("机器码", self.machine_verify_id)
        r1 = QHBoxLayout()
        for t, fn in [("验证使用", self.verify_machine), ("网络测试", self.test_net), ("版本检测", self.check_version)]:
            b = QPushButton(t); b.clicked.connect(fn); r1.addWidget(b)
        r1.addStretch(1); w1 = QWidget(); w1.setLayout(r1); f1.addRow("", w1)
        p2 = QWidget(); f2 = QFormLayout(p2)
        self.machine_recharge_id = QLineEdit(get_machine_code())
        self.mc_ka = QLineEdit(); self.mc_pwd = QLineEdit()
        self.mc_pwd.setEchoMode(QLineEdit.Password)
        self.mc_pwd.setPlaceholderText("没有密码请留空")
        f2.addRow("机器码", self.machine_recharge_id); f2.addRow("充值卡号", self.mc_ka); f2.addRow("充值密码", self.mc_pwd)
        r2 = QHBoxLayout()
        for t, fn in [
            ("确认充值", self.activate),
            ("一键支付续费充值", lambda: webbrowser.open(renew_url_for_user(self.machine_recharge_id.text()))),
            ("购买充值卡", lambda: webbrowser.open(cfg.CARD_GEN_URL)),
            ("购买库存卡", lambda: webbrowser.open(cfg.CARD_STOCK_URL)),
        ]:
            b = QPushButton(t); b.clicked.connect(fn); r2.addWidget(b)
        r2.addStretch(1); w2 = QWidget(); w2.setLayout(r2); f2.addRow("", w2)
        self.machine_verify_id.textChanged.connect(self._sync_machine_id_to_recharge)
        self.machine_recharge_id.textChanged.connect(self._sync_machine_id_to_verify)
        sub.addTab(p1, "机器码验证使用")
        sub.addTab(p2, "机器码充值续费")
        self.tabs.addTab(page, "一键注册机器码账号")

    def _sync_machine_id_to_recharge(self, text: str) -> None:
        if self.machine_recharge_id.text() != text:
            self.machine_recharge_id.setText(text)

    def _sync_machine_id_to_verify(self, text: str) -> None:
        if self.machine_verify_id.text() != text:
            self.machine_verify_id.setText(text)

    def _set_ready(self, ready: bool) -> None:
        self.ready = ready
        self.status_txt.setText("已连接" if ready else "未连接")
        self.status_dot.setStyleSheet("color: green;" if ready else "color: orange;")

    def _need_ready(self) -> bool:
        if self.ready:
            return True
        QMessageBox.warning(self, "提示", "尚未连接服务器，请先初始化。")
        return False

    def bootstrap(self) -> None:
        self._set_ready(False)
        self.notice.setPlainText("正在连接服务器...")
        def work() -> str:
            self.client.bootstrap()
            return self.client.get_notice().message() or "暂无公告"
        def done(res: Any) -> None:
            if isinstance(res, InitFailedError):
                short = res.args[0] if res.args else "初始化失败"
                self.notice.setPlainText(
                    f"初始化失败（见控制台 [BSPHP] 与弹窗「显示详细信息」）\n{short}"
                )
                self.status_line.setText(short)
                box = QMessageBox(self)
                box.setIcon(QMessageBox.Icon.Critical)
                box.setWindowTitle("初始化失败")
                box.setText(short)
                if res.debug_log:
                    box.setDetailedText(res.debug_log)
                box.exec()
                return
            if isinstance(res, Exception):
                self.notice.setPlainText(f"初始化失败: {res}")
                self.status_line.setText(repr(res))
                return
            self._set_ready(True)
            self.notice.setPlainText(res)
        run_async(work, done)

    def test_net(self) -> None:
        if not self._need_ready():
            return
        run_async(lambda: self.client.connect(), lambda ok: self.status_line.setText("网络连接正常" if ok else "网络连接异常"))

    def check_version(self) -> None:
        if not self._need_ready():
            return
        run_async(self.client.get_version, lambda r: self.status_line.setText("版本获取失败" if isinstance(r, Exception) else (f"当前版本：{r.message()}" if r.message() else "版本获取失败")))

    def verify_card(self) -> None:
        if not self._need_ready():
            return
        cid = self.card_id.text().strip()
        if not cid:
            self.status_line.setText("请输入卡串")
            return
        def work() -> tuple[APIResult, str]:
            r = self.client.login_ic(cid, self.card_pwd.text().strip())
            exp = self.client.get_date_ic().message() or "-"
            return r, exp
        def done(res: Any) -> None:
            if isinstance(res, Exception):
                self.status_line.setText(repr(res))
                return
            r, exp = res
            msg = r.message() or "验证失败"
            self.status_line.setText(msg)
            if r.code == 1081 or "1081" in msg:
                self.logged_id = cid
                self._open_panel(cid, exp)
                self.status_line.setText("验证成功，主控制面板已在新窗口打开")
        run_async(work, done)

    def verify_machine(self) -> None:
        if not self._need_ready():
            return
        mid = self.machine_verify_id.text().strip()
        if not mid:
            self.status_line.setText("【机器码】请输入机器码（账号）")
            return
        g = self.client.machine_code
        def work() -> tuple[APIResult, APIResult, str]:
            feat = self.client.add_card_features(mid, g, g)
            r = self.client.login_ic(mid, "", key=g, maxoror=g)
            exp = self.client.get_date_ic().message() or "-"
            return feat, r, exp
        def done(res: Any) -> None:
            if isinstance(res, Exception):
                self.status_line.setText(repr(res)); return
            feat, r, exp = res
            fm = feat.message() or "（无 data）"
            if not (feat.code in (1011, 1081) or "1081" in fm or "成功" in fm):
                self.status_line.setText(f"[AddCardFeatures.key.ic] code={feat.code} {fm}")
                return
            msg = r.message() or "验证失败"
            if r.code == 1081 or "1081" in msg:
                self.logged_id = mid
                self._open_panel(mid, exp)
                self.status_line.setText("验证成功（机器码账号），主控制面板已在新窗口打开")
            else:
                self.status_line.setText(f"[login.ic] {msg}")
        run_async(work, done)

    def activate(self) -> None:
        if not self._need_ready():
            return
        icid = self.machine_recharge_id.text().strip()
        ka = self.mc_ka.text().strip()
        if not icid:
            self.status_line.setText("【机器码】请输入机器码（账号）"); return
        if not ka:
            self.status_line.setText("请输入充值卡号"); return
        pwd = self.mc_pwd.text().strip()
        run_async(lambda: self.client.recharge_card(icid, ka, pwd), lambda r: self.status_line.setText(repr(r) if isinstance(r, Exception) else f"[chong.ic] code={r.code} {r.message() or '（无 data）'}"))

    def _open_panel(self, logged_id: str, vip_exp: str) -> None:
        if self.panel:
            self.panel.close()
        self.panel = CardControlPanel(self, self.client, logged_id, vip_exp)
        self.panel.show()


def main() -> None:
    os.chdir(os.path.dirname(os.path.abspath(__file__)))
    app = QApplication(sys.argv)
    app.setStyleSheet(INPUT_FIELD_QSS)
    w = CardDemoQt()
    w.show()
    sys.exit(app.exec())


if __name__ == "__main__":
    main()
