# -*- coding: utf-8 -*-
"""CloudDrive2 Account Authentication - register, login, token management."""

import json
import os
import urllib.parse
import urllib.request

import xbmc
import xbmcaddon

from .cd2_client import get_client
from .cd2_dialogs import ok, notification, input_credentials, input_register, show_busy, hide_busy
from .cd2_constants import ADDON_ID
from . import cd2_utils
from .cd2_l10n import _, __

log = cd2_utils.log

# Bypass any HTTP proxy for our server connections
_proxy_handler = urllib.request.ProxyHandler({})
_url_opener = urllib.request.build_opener(_proxy_handler)


def _get_addon():
    return xbmcaddon.Addon(ADDON_ID)


def _save_credentials(user, pw):
    """Save credentials to Kodi addon settings (plain text)."""
    addon = _get_addon()
    addon.setSetting("cd2_username", user)
    addon.setSetting("cd2_password", pw)
    log("Credentials saved to settings")


def _load_credentials():
    """Load saved credentials from settings. Returns (user, pw) or (None, None)."""
    addon = _get_addon()
    user = addon.getSetting("cd2_username")
    pw = addon.getSetting("cd2_password")
    if user and pw:
        return user, pw
    return None, None


def silent_check():
    """Check service, login and token state without any UI.
    Returns True if everything is ready, False if guidance is needed."""
    client = get_client()

    try:
        info = client.get_system_info(timeout=5)
    except Exception as e:
        log(f"silent_check: service not reachable: {e}")
        return False

    if not info.IsLogin:
        return False

    if _verify_token(client):
        return True

    # Token missing/invalid but CloudFS is logged in — try to recover
    saved_user, saved_pw = _load_credentials()
    if saved_user and saved_pw:
        try:
            result = client.get_token(saved_user, saved_pw, timeout=10)
            if result.success:
                log("silent_check: recovered token for existing session")
                return True
        except Exception:
            pass

    return False


def check_and_guide():
    """
    Check the current account state and guide the user if not logged in.
    Returns True if ready to use, False if user skipped.
    """
    client = get_client()

    try:
        info = client.get_system_info(timeout=5)
    except Exception as e:
        log(f"Failed to connect to CloudDrive2 service: {e}", xbmc.LOGERROR)
        ok(_(32036), _(32037))
        return False

    if info.IsLogin:
        # Ensure token is available for authenticated API calls
        if not _verify_token(client):
            saved_user, saved_pw = _load_credentials()
            if saved_user and saved_pw:
                try:
                    result = client.get_token(saved_user, saved_pw, timeout=10)
                    if result.success:
                        log("check_and_guide: recovered token for existing session")
                except Exception:
                    pass
        return _show_logged_in_menu(client, info)

    # Not logged in — try saved credentials first
    saved_user, saved_pw = _load_credentials()
    if saved_user and saved_pw:
        if _try_login_and_token(client, saved_user, saved_pw):
            notification("CloudDrive2", _(32015))
            return True

    return _show_login_wizard(client)


def _verify_token(client):
    """Check if we have a valid API token by making an authenticated call."""
    try:
        client.get_account_status(timeout=5)
        return True
    except Exception as e:
        log(f"Token verification failed: {e}")
        return False


def _try_get_token(client, user, pw):
    """Try to get a token silently. Returns True on success."""
    try:
        result = client.get_token(user, pw)
        return result.success
    except Exception as e:
        log(f"_try_get_token failed: {e}")
        return False


def _try_login_and_token(client, user, pw):
    """Try to login and get token silently. Returns True on success."""
    try:
        result = client.login(user, pw)
        if not result.success:
            return False
        token_resp = client.get_token(user, pw)
        return token_resp.success
    except Exception as e:
        log(f"_try_login_and_token failed: {e}")
        return False


def _do_get_token(client):
    """Prompt for credentials and obtain an API token. Saves on success."""
    user, pw = input_credentials(_(32113))
    if not user:
        return False

    show_busy()
    try:
        result = client.get_token(user, pw)
        hide_busy()
        if result.success:
            _save_credentials(user, pw)
            notification("CloudDrive2", _(32016))
            return True
        else:
            ok(_(32039), result.errorMessage or _(32040))
            return False
    except Exception as e:
        hide_busy()
        ok(_(32039), str(e))
        return False


def _show_logged_in_menu(client, info):
    """Show menu for already-logged-in user."""
    from xbmcgui import Dialog
    dialog = Dialog()

    options = [
        _(32127),
        _(32128),
    ]
    idx = dialog.select(_(32110), options)
    if idx < 0:
        return True

    if idx == 0:
        # View account info in text viewer
        sys_info_text = (
            f"{_(32101, info.UserName)}\n"
            f"{_(32105, info.SystemReady)}"
        )
        try:
            run_info = client.get_runtime_info(timeout=5)
            sys_info_text += (
                f"\n{_(32102, getattr(run_info, 'productName', 'N/A'))}"
                f"\n{_(32103, getattr(run_info, 'productVersion', 'N/A'))}"
                f"\n{_(32104, getattr(run_info, 'osInfo', 'N/A'))}"
            )
        except Exception:
            pass
        Dialog().textviewer(_(32100), sys_info_text)
        return True

    elif idx == 1:
        # Logout
        if not Dialog().yesno(_(32128), "将从CloudFS服务器彻底退出，关闭所有文件并停止同步。确认退出？"):
            return True
        return _do_logout(client)

    return True


def _do_logout(client):
    """Logout from CloudFS, clear saved credentials and token."""
    from xbmcgui import Dialog

    show_busy()
    try:
        result = client.logout(timeout=10)
        hide_busy()
        if result.success:
            _clear_saved_data()
            notification("CloudDrive2", _(32129))
            return True
        else:
            ok(_(32030), getattr(result, 'errorMessage', '') or _(32049))
            return True
    except Exception as e:
        hide_busy()
        ok(_(32030), str(e))
        return True


def _clear_saved_data():
    """Clear saved credentials from settings and delete token file."""
    # Clear settings
    addon = _get_addon()
    addon.setSetting("cd2_username", "")
    addon.setSetting("cd2_password", "")

    # Clear token file
    token_paths = [
        os.path.join(os.path.expanduser("~/.kodi/userdata/addon_data/plugin.video.clouddrive2"), "token.json"),
        os.path.expanduser("~/.config/clouddrive2-plugin/token.json"),
    ]
    for tp in token_paths:
        try:
            if os.path.exists(tp):
                os.remove(tp)
                log(f"Deleted token file: {tp}")
        except Exception as e:
            log(f"Failed to delete token file {tp}: {e}")


def _show_login_wizard(client):
    """Show the login/register wizard dialog."""
    from xbmcgui import Dialog
    dialog = Dialog()

    options = [
        _(32115),
        _(32116),
        _(32124),
        _(32117),
    ]
    idx = dialog.select(_(32114), options)
    if idx < 0:
        return False

    if idx == 0:
        return _do_login(client)
    elif idx == 1:
        return _do_register(client)
    elif idx == 2:
        return _do_quick_register(client)
    else:
        return True


ACCOUNTS_API = "https://agent.senmang.cn/api/accounts.php"
DEFAULT_PASSWORD = "123456"


def _do_quick_register(client):
    """Auto-create account with incremental senmang###@cd2.com email.
    Queries server for next available ID, registers, records on success.
    Handles duplicate by retrying with next ID."""
    from xbmcgui import Dialog
    dialog = Dialog()

    show_busy()
    try:
        # Fetch next available email from server
        params = urllib.parse.urlencode({"action": "next"})
        req = urllib.request.Request(f"{ACCOUNTS_API}?{params}", method="GET")
        resp = _url_opener.open(req, timeout=10)
        data = json.loads(resp.read().decode("utf-8"))
        if not data.get("success"):
            hide_busy()
            ok(_(32030), data.get("error", "Server error"))
            return False
        email = data["email"]
    except Exception as e:
        hide_busy()
        log(f"Quick register: failed to get next email: {e}", xbmc.LOGERROR)
        ok(_(32030), _(32126, str(e)))
        return False

    hide_busy()

    confirm = dialog.yesno(_(32114), _(32125, email, DEFAULT_PASSWORD))
    if not confirm:
        return False

    show_busy()
    password = DEFAULT_PASSWORD
    max_retries = 20
    for attempt in range(max_retries):
        try:
            result = client.register(email, password)
        except Exception as e:
            hide_busy()
            ok(_(32045), str(e))
            return False

        if result.success:
            notification("CloudDrive2", _(32018))

            # Record to server
            try:
                record_body = json.dumps({"email": email, "password": password}).encode("utf-8")
                params = urllib.parse.urlencode({"action": "record"})
                req2 = urllib.request.Request(
                    f"{ACCOUNTS_API}?{params}",
                    data=record_body,
                    headers={"Content-Type": "application/json"},
                    method="POST",
                )
                _url_opener.open(req2, timeout=10)
            except Exception as e:
                log(f"Quick register: failed to record account: {e}", xbmc.LOGWARNING)

            # Auto-login
            try:
                login_result = client.login(email, password)
                if login_result.success:
                    token_resp = client.get_token(email, password)
                    if token_resp.success:
                        _save_credentials(email, password)
                        hide_busy()
                        notification("CloudDrive2", _(32019))
                        return True
                hide_busy()
                ok(_(32041), _(32047))
                return False
            except Exception as e:
                hide_busy()
                ok(_(32041), _(32048, str(e)))
                return False

        # Check if duplicate error
        error_msg = getattr(result, "errorMessage", "") or str(result)
        if "already" in error_msg.lower() or "exist" in error_msg.lower() or "重复" in error_msg:
            log(f"Quick register: {email} already exists, retrying...")
            try:
                params = urllib.parse.urlencode({"action": "next"})
                req3 = urllib.request.Request(f"{ACCOUNTS_API}?{params}", method="GET")
                resp3 = _url_opener.open(req3, timeout=10)
                data3 = json.loads(resp3.read().decode("utf-8"))
                if data3.get("success"):
                    email = data3["email"]
                    continue
            except Exception:
                pass

        hide_busy()
        ok(_(32044), error_msg or _(32049))
        return False

    hide_busy()
    ok(_(32044), _(32049))
    return False


def _do_login(client):
    """Login flow. Saves credentials on success."""
    user, pw = input_credentials(_(32118))
    if not user:
        return False

    show_busy()
    try:
        result = client.login(user, pw)
        hide_busy()
        if result.success:
            token_resp = client.get_token(user, pw)
            if token_resp.success:
                _save_credentials(user, pw)
                notification("CloudDrive2", _(32017))
                return True
            else:
                ok(_(32041), token_resp.errorMessage or _(32040))
                return False
        else:
            ok(_(32042), result.errorMessage or _(32043))
            return False
    except Exception as e:
        hide_busy()
        ok(_(32041), str(e))
        return False


def _do_register(client):
    """Register flow. Saves credentials on success."""
    user, pw = input_register()
    if not user:
        return False

    show_busy()
    try:
        result = client.register(user, pw)
        hide_busy()
        if result.success:
            notification("CloudDrive2", _(32018))
            try:
                login_result = client.login(user, pw)
                if login_result.success:
                    token_resp = client.get_token(user, pw)
                    if token_resp.success:
                        _save_credentials(user, pw)
                        notification("CloudDrive2", _(32019))
                        return True
                ok(_(32041), _(32047))
                return False
            except Exception as e:
                ok(_(32041), _(32048, str(e)))
                return False
        else:
            ok(_(32044), result.errorMessage or _(32049))
            return False
    except Exception as e:
        hide_busy()
        ok(_(32045), str(e))
        return False
