from __future__ import annotations

import os
import re
import subprocess
import sys
from pathlib import Path


ALLOW_EXTERNAL_SOURCE_ENV = "WAWA_ALLOW_EXTERNAL_SOURCE_DIR"
ALLOW_LEGACY_DESKTOP_SOURCE_ENV = "WAWA_ALLOW_LEGACY_DESKTOP_SOURCE"
os.environ.setdefault("WAWA_DIALOG_ICON_FILENAME", "app_dialog_icon.ico")
os.environ.setdefault("WAWA_DIALOG_LOGO_FILENAME", "logo_app_68.png")


def _desktop_dir() -> Path:
    """返回当前 Windows 用户桌面路径，兼容桌面路径不存在时的兜底。"""
    try:
        desktop = Path.home() / "Desktop"
        if desktop.exists():
            return desktop
    except Exception:
        pass
    return Path.cwd()


def _is_project_source_dir(path: Path) -> bool:
    """判断一个目录是否是可热更新源码根目录。"""
    return (path / "launcher" / "app.py").exists() and (path / "common" / "shared.py").exists()


def _hot_update_candidates() -> list[Path]:
    """按优先级寻找外置源码目录，避免新版 exe 被旧桌面源码抢走。"""
    candidates: list[Path] = []
    frozen = getattr(sys, "frozen", False)
    env_source = os.environ.get("WAWA_HOT_UPDATE_SOURCE_DIR", "").strip()
    if env_source and (not frozen or os.environ.get(ALLOW_EXTERNAL_SOURCE_ENV, "").strip() == "1"):
        candidates.append(Path(env_source))

    # 源码运行时，当前 main.py 所在目录就是源码根目录。
    if not frozen:
        candidates.append(Path(__file__).resolve().parent)

    # 打包 exe 放在便携包根目录时，优先读取 exe 同级 source 目录。
    exe_dir = Path(sys.executable).resolve().parent if frozen else Path.cwd()
    candidates.append(exe_dir / "source")

    # 旧桌面固定目录只作为人工调试开关，正常用户下载新版时不能加载旧源码。
    if os.environ.get(ALLOW_LEGACY_DESKTOP_SOURCE_ENV, "").strip() == "1":
        candidates.append(_desktop_dir() / "WaWaCloud" / "source")
    return candidates


def _activate_hot_update_source() -> None:
    """把外置源码目录放到导入路径最前面，让菜单“界面更新”能重载新代码。"""
    for candidate in _hot_update_candidates():
        try:
            source_dir = candidate.resolve()
        except OSError:
            continue
        if not _is_project_source_dir(source_dir):
            continue
        source_text = str(source_dir)
        if source_text not in sys.path:
            sys.path.insert(0, source_text)
        os.environ["WAWA_HOT_UPDATE_SOURCE_DIR"] = source_text
        if source_dir.name.lower() == "source":
            portable_root = source_dir.parent
            os.environ.setdefault("WAWA_PORTABLE_ROOT", str(portable_root))
            os.environ.setdefault("WAWA_APP_DATA_DIR", str(portable_root / "data"))
        try:
            os.chdir(source_text)
        except OSError:
            pass
        return


_activate_hot_update_source()

try:
    from common.package_metadata_fallbacks import ensure_package_metadata_fallbacks

    ensure_package_metadata_fallbacks()
except Exception:
    pass

try:
    from common.codec_fallbacks import ensure_idna_codec

    ensure_idna_codec()
except Exception:
    pass

if len(sys.argv) > 1 and sys.argv[1] == "--task-worker":
    from common.task_worker import main as task_worker_main

    raise SystemExit(task_worker_main(sys.argv[2:]))

if len(sys.argv) > 1 and sys.argv[1] == "--credential-web-login":
    from common.credential_web_login import main as credential_web_login_main

    raise SystemExit(credential_web_login_main(sys.argv[2:]))

if len(sys.argv) > 1 and sys.argv[1] == "--huawei-wwwroot-worker":
    # 华为云自动购买 worker 是无界面子进程，提前分流可避免打包 exe 子进程加载 Tk 界面层。
    from HUAWEI.source_runner import run_huawei_wwwroot_worker

    raise SystemExit(run_huawei_wwwroot_worker())

def _read_app_version() -> str:
    shared_path = Path(__file__).resolve().parent / "common" / "shared.py"
    try:
        text = shared_path.read_text(encoding="utf-8", errors="ignore")
    except Exception:
        return "6.18.59"
    match = re.search(r'^APP_VERSION\s*=\s*[\'"]([^\'"]+)[\'"]', text, re.M)
    return match.group(1).strip() if match else "6.18.59"


def _show_recovery_message(title: str, message: str) -> None:
    print(f"{title}: {message}")
    try:
        import tkinter as tk
        from common.ui_helpers import show_app_message_dialog

        root = tk.Tk()
        root.withdraw()
        try:
            root.attributes("-topmost", True)
        except tk.TclError:
            pass
        show_app_message_dialog(root, title, message, modal=True)
        root.destroy()
    except Exception:
        pass


def _recover_from_startup_import_error(error: BaseException) -> bool:
    try:
        from common.update_guard import UPDATE_FAILED_CONTACT_MESSAGE, check_latest_version, perform_auto_update

        check_result = check_latest_version(_read_app_version())
        if check_result.auto_update_available:
            update_result = perform_auto_update(check_result)
            if update_result.ok:
                if not update_result.external_restart:
                    if getattr(sys, "frozen", False):
                        command = [sys.executable]
                        cwd = str(Path(sys.executable).resolve().parent)
                    else:
                        command = [sys.executable, *sys.argv]
                        cwd = os.getcwd()
                    subprocess.Popen(command, cwd=cwd, close_fds=True)
                return True
            _show_recovery_message("自动修复失败", UPDATE_FAILED_CONTACT_MESSAGE)
            return False
        if check_result.needs_update:
            _show_recovery_message("需要更新", UPDATE_FAILED_CONTACT_MESSAGE)
            return False
    except Exception as update_error:
        _show_recovery_message(
            "启动失败",
            f"软件启动模块加载失败，自动修复也未完成。\n\n{update_error}\n\n请联系客户经理处理。",
        )
        return False

    _show_recovery_message(
        "启动失败",
        f"软件启动模块加载失败。\n\n错误信息：{error}\n\n请联系客户经理处理。",
    )
    return False


try:
    from launcher.app import main
except Exception as exc:
    if _recover_from_startup_import_error(exc):
        raise SystemExit(0)
    raise SystemExit(1)


if __name__ == "__main__":
    main()
