"""
FWAuto Authentication Module

用戶認證與 token 管理：
1. 檢查本地是否有有效的 user_token
2. 沒有則開啟瀏覽器進行 Google SSO 登入
3. 登入後儲存 token 到本地
4. 提供 token 給其他模組使用（如用量回報）
"""

import json
import os
import time
import webbrowser
from http.server import BaseHTTPRequestHandler, HTTPServer
from pathlib import Path
from threading import Thread
from urllib.parse import parse_qs, urlparse

import requests

from .logging_config import get_logger

# ============================================================
# API 模式
# ============================================================


def is_direct_api_mode() -> bool:
    """
    檢查是否使用直連模式（Claude Max 訂閱）。

    當環境變數 FWAUTO_API_MODE=direct 時，使用本機 Claude Max 訂閱，
    繞過 API proxy，適用於開發和測試環境。

    Returns:
        bool: True 表示使用直連模式
    """
    return os.environ.get("FWAUTO_API_MODE", "").lower() == "direct"


# ============================================================
# 配置
# ============================================================

# FWAuto Server URL
FWAUTO_SERVER_URL = "https://fwauto-server-189969833984.asia-east1.run.app"

# 本地配置檔案路徑
AUTH_CONFIG_FILE = Path.home() / ".fwauto_auth.json"

# 本地 callback server port
CALLBACK_PORT = 8888

# 登入超時時間（秒）
LOGIN_TIMEOUT = 300


# ============================================================
# Callback Handler
# ============================================================


class _AuthCallbackHandler(BaseHTTPRequestHandler):
    """處理 OAuth 回調"""

    auth_result = None

    def do_GET(self):
        """處理 GET 請求"""
        if self.path.startswith("/callback"):
            parsed = urlparse(self.path)
            params = parse_qs(parsed.query)

            if "user_token" in params and "email" in params:
                _AuthCallbackHandler.auth_result = {
                    "user_token": params["user_token"][0],
                    "email": params["email"][0],
                    "name": params.get("name", [params["email"][0].split("@")[0]])[0],
                }

                # 返回成功頁面
                self.send_response(200)
                self.send_header("Content-type", "text/html; charset=utf-8")
                self.end_headers()

                html = """
                <!DOCTYPE html>
                <html>
                <head>
                    <meta charset="utf-8">
                    <title>FWAuto - Login Successful</title>
                    <style>
                        body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
                               text-align: center; padding: 50px; background: #f5f5f5; }
                        .container { background: white; padding: 40px; border-radius: 10px;
                                    max-width: 500px; margin: 0 auto; box-shadow: 0 2px 10px rgba(0,0,0,0.1); }
                        .success { color: #4CAF50; font-size: 48px; margin: 0; }
                        h1 { color: #333; margin: 20px 0; }
                        p { color: #666; }
                    </style>
                </head>
                <body>
                    <div class="container">
                        <div class="success">✅</div>
                        <h1>Login Successful!</h1>
                        <p>You can close this window and return to the terminal to continue using FWAuto.</p>
                    </div>
                </body>
                </html>
                """
                self.wfile.write(html.encode("utf-8"))
            else:
                self.send_response(400)
                self.send_header("Content-type", "text/html; charset=utf-8")
                self.end_headers()
                self.wfile.write(b"<h1>Login failed</h1>")
        else:
            self.send_response(404)
            self.end_headers()

    def log_message(self, format, *args):
        """禁用日誌輸出"""
        pass


# ============================================================
# 認證管理
# ============================================================


class AuthManager:
    """FWAuto 認證管理器"""

    def __init__(self, server_url: str = FWAUTO_SERVER_URL):
        self.server_url = server_url
        self.config_file = AUTH_CONFIG_FILE
        self._user_token: str | None = None
        self._user_email: str | None = None
        self._user_name: str | None = None
        self.logger = get_logger("auth")

    def _load_config(self) -> bool:
        """從本地載入配置"""
        if not self.config_file.exists():
            return False

        try:
            with open(self.config_file, encoding="utf-8") as f:
                config = json.load(f)
                self._user_token = config.get("user_token")
                self._user_email = config.get("email")
                self._user_name = config.get("name")
                return bool(self._user_token)
        except Exception as e:
            self.logger.debug(f"Failed to load auth config: {e}")
            return False

    def _save_config(self):
        """儲存配置到本地"""
        try:
            config = {
                "user_token": self._user_token,
                "email": self._user_email,
                "name": self._user_name,
                "server_url": self.server_url,
            }
            with open(self.config_file, "w", encoding="utf-8") as f:
                json.dump(config, f, indent=2, ensure_ascii=False)
            self.logger.debug(f"Auth config saved to {self.config_file}")
        except Exception as e:
            self.logger.error(f"Failed to save auth config: {e}")

    def _verify_token(self, retries: int = 2) -> tuple[bool, str]:
        """
        驗證 token 是否有效

        Args:
            retries: 重試次數（處理 Cloud Run 冷啟動）

        Returns:
            tuple[bool, str]: (是否有效, 狀態訊息)
            - (True, "valid") - token 有效
            - (False, "invalid") - token 無效或已過期
            - (False, "network_error") - 網路錯誤（非 token 問題）
            - (False, "timeout") - 請求超時（可能是冷啟動）
        """
        if not self._user_token:
            return False, "invalid"

        last_error = None
        for attempt in range(retries + 1):
            try:
                # 第一次用較短 timeout，後續 retry 用較長的（處理冷啟動）
                timeout = 5 if attempt == 0 else 15
                response = requests.get(
                    f"{self.server_url}/api/usage",
                    headers={"Authorization": f"Bearer {self._user_token}"},
                    timeout=timeout,
                )
                if response.status_code == 200:
                    return True, "valid"
                elif response.status_code == 401:
                    return False, "invalid"
                else:
                    last_error = f"server_error_{response.status_code}"
            except requests.exceptions.Timeout:
                last_error = "timeout"
                if attempt < retries:
                    self.logger.debug(f"Token verify timeout, retrying ({attempt + 1}/{retries})...")
                    continue
            except requests.exceptions.ConnectionError:
                last_error = "network_error"
                break
            except Exception as e:
                last_error = "network_error"
                self.logger.debug(f"Token verify error: {e}")
                break

        return False, last_error or "network_error"

    def _do_login(self, use_dev_login: bool = False) -> bool:
        """Execute login flow"""
        print()
        print("=" * 60)
        print("🔐 FWAuto Login Required")
        print("=" * 60)
        print()

        # Reset callback handler state
        _AuthCallbackHandler.auth_result = None

        # Start local callback server
        try:
            server = HTTPServer(("localhost", CALLBACK_PORT), _AuthCallbackHandler)
        except OSError as e:
            print(f"❌ Failed to start callback server (port {CALLBACK_PORT}): {e}")
            return False

        server_thread = Thread(target=server.serve_forever, daemon=True)
        server_thread.start()

        # Build login URL
        callback_url = f"http://localhost:{CALLBACK_PORT}/callback"

        if use_dev_login:
            login_url = f"{self.server_url}/auth/dev-login?email=dev@example.com&callback={callback_url}"
            print("🔧 Using development mode login...")
        else:
            login_url = f"{self.server_url}/auth/login?callback={callback_url}"
            print("📝 Login process:")
            print("   1. Opening browser for Google login")
            print("   2. Will return automatically after login")
            print()

        print("🌐 Opening browser...")
        webbrowser.open(login_url)

        print()
        print("⏳ Waiting for login...")
        if not use_dev_login:
            print("   (Please complete login in browser)")
        print()

        # Wait for callback
        start_time = time.time()
        while _AuthCallbackHandler.auth_result is None:
            if time.time() - start_time > LOGIN_TIMEOUT:
                print("❌ Login timeout")
                server.shutdown()
                return False
            time.sleep(0.5)

        # Shutdown server
        server.shutdown()

        # Process result
        result = _AuthCallbackHandler.auth_result
        self._user_token = result["user_token"]
        self._user_email = result["email"]
        self._user_name = result["name"]

        print("=" * 60)
        print("✅ Login successful!")
        print("=" * 60)
        print(f"   User: {self._user_name} ({self._user_email})")
        print()

        # Save config
        self._save_config()

        return True

    def ensure_authenticated(self, use_dev_login: bool = False) -> bool:
        """
        確保用戶已認證

        Args:
            use_dev_login: 是否使用開發模式登入（不需要 Google OAuth）

        Returns:
            bool: 是否認證成功
        """
        # 1. 嘗試載入本地配置
        if self._load_config():
            # 2. 驗證 token 是否有效
            is_valid, status = self._verify_token()
            if is_valid:
                self.logger.debug(f"Authenticated as {self._user_email}")
                return True
            elif status == "invalid":
                self.logger.debug("Token expired or invalid")
            else:
                # 網路錯誤 - 假設 token 仍有效，讓後續 API 呼叫處理
                self.logger.debug(f"Token verify failed ({status}), assuming valid")
                return True

        # 3. 需要登入
        return self._do_login(use_dev_login=use_dev_login)

    @property
    def user_token(self) -> str | None:
        """取得 user token"""
        return self._user_token

    @property
    def user_email(self) -> str | None:
        """取得用戶 email"""
        return self._user_email

    @property
    def user_name(self) -> str | None:
        """取得用戶名稱"""
        return self._user_name

    @property
    def is_authenticated(self) -> bool:
        """檢查是否已認證"""
        return bool(self._user_token)

    def logout(self):
        """登出（清除本地配置）"""
        self._user_token = None
        self._user_email = None
        self._user_name = None

        if self.config_file.exists():
            self.config_file.unlink()
            print("✅ Logged out, config cleared")


# ============================================================
# 全域實例
# ============================================================

# 全域 AuthManager 實例
_auth_manager: AuthManager | None = None


def get_auth_manager() -> AuthManager:
    """取得全域 AuthManager 實例"""
    global _auth_manager
    if _auth_manager is None:
        _auth_manager = AuthManager()
    return _auth_manager


def get_user_token() -> str | None:
    """
    取得當前用戶的 token

    這是給其他模組（如 ai_brain.py）使用的簡便函數
    """
    # 先嘗試從已載入的 AuthManager 取得
    if _auth_manager and _auth_manager.user_token:
        return _auth_manager.user_token

    # 否則從配置檔案讀取
    if AUTH_CONFIG_FILE.exists():
        try:
            with open(AUTH_CONFIG_FILE, encoding="utf-8") as f:
                config = json.load(f)
                return config.get("user_token")
        except Exception:
            pass

    return None


def get_auth_server_url() -> str:
    """取得認證伺服器 URL"""
    if AUTH_CONFIG_FILE.exists():
        try:
            with open(AUTH_CONFIG_FILE, encoding="utf-8") as f:
                config = json.load(f)
                return config.get("server_url", FWAUTO_SERVER_URL)
        except Exception:
            pass
    return FWAUTO_SERVER_URL


def get_display_name() -> str:
    """取得使用者顯示名稱：name > email 前綴 > You"""
    if AUTH_CONFIG_FILE.exists():
        try:
            with open(AUTH_CONFIG_FILE, encoding="utf-8") as f:
                config = json.load(f)
                if name := config.get("name"):
                    return name
                if email := config.get("email"):
                    return email.split("@")[0]
        except Exception:
            pass
    return "You"


# ============================================================
# CLI 入口
# ============================================================


def cli_login(dev: bool = False):
    """CLI 登入命令"""
    auth = get_auth_manager()
    auth.ensure_authenticated(use_dev_login=dev)


def cli_logout():
    """CLI 登出命令"""
    auth = get_auth_manager()
    auth.logout()


def cli_status():
    """CLI show login status"""
    auth = get_auth_manager()

    if auth._load_config():
        print()
        print("📋 FWAuto Auth Status")
        print("=" * 40)
        print("   Status: ✅ Logged in")
        print(f"   User: {auth.user_name}")
        print(f"   Email: {auth.user_email}")
        print(f"   Server: {auth.server_url}")
        print(f"   Dashboard: {auth.server_url}/dashboard")
        print()

        # Verify token with detailed status
        print("   Verifying token...", end=" ", flush=True)
        is_valid, status = auth._verify_token()
        print("\r" + " " * 30 + "\r", end="")  # Clear "Verifying..." message

        if is_valid:
            print("   Token: ✅ Valid")
        elif status == "invalid":
            print("   Token: ❌ Invalid or expired, please login again")
        elif status == "timeout":
            print("   Token: ⚠️ Server timeout (Cold start?), token assumed valid")
        elif status == "network_error":
            print("   Token: ⚠️ Network error, cannot verify (token assumed valid)")
        else:
            print(f"   Token: ⚠️ {status}, cannot verify")
        print()
    else:
        print()
        print("📋 FWAuto Auth Status")
        print("=" * 40)
        print("   Status: ❌ Not logged in")
        print()
        print("   Run 'fwauto auth login' to login")
        print(f"   Dashboard: {FWAUTO_SERVER_URL}/dashboard")
        print()
