from pathlib import Path
import signal

import click
import tomli as tomllib

from .._utils import PROMPT_PREFIX
from ..config import settings
from ..lib._http import HttpClient


def _load_config(path: Path) -> dict | None:
    if not path.exists():
        return None
    try:
        with open(path, "rb") as f:
            data = tomllib.load(f)
        if not all(k in data for k in ("username", "user_id", "api_key")):
            return None
        return data
    except Exception:
        return None


def _save_config(path: Path, user_info: dict) -> None:
    try:
        path.parent.mkdir(parents=True, exist_ok=True)
        with open(path, "w", encoding="utf-8") as f:
            f.write(f'username = "{user_info["username"]}"\n')
            f.write(f'user_id = "{user_info["user_id"]}"\n')
            f.write(f'api_key = "{user_info["api_key"]}"\n')
            f.write(f'created_at = "{user_info["created_at"]}"\n')
        try:
            path.chmod(0o600)
        except Exception:
            pass
    except Exception as e:
        raise click.ClickException(f"Failed to save config file: {e}") from None


def get_saved_api_key() -> str | None:
    data = _load_config(settings.config_path)
    if not data:
        return None
    api_key = str(data.get("api_key", "")).strip()
    return api_key or None


def _prompt_api_key() -> str:
    click.echo(
        PROMPT_PREFIX
        + "You can find your API key at: "
        + click.style("https://pytrio.cn/dashboard", fg=(229, 229, 18))
    )
    original_sigint_handler = signal.getsignal(signal.SIGINT)
    try:
        signal.signal(signal.SIGINT, signal.default_int_handler)
        try:
            api_key = click.prompt(
                PROMPT_PREFIX
                + "Paste an API key from your profile and hit enter, or press 'Ctrl+C' to quit",
                type=str,
                hide_input=True,
            )
        except KeyboardInterrupt:
            raise click.Abort() from None
    finally:
        signal.signal(signal.SIGINT, original_sigint_handler)

    api_key = str(api_key).strip()
    if not api_key:
        raise click.ClickException(PROMPT_PREFIX + "API key cannot be empty")

    return api_key


def _check_api_key(http_client: HttpClient, api_key: str) -> dict:
    try:
        return http_client.check_user(api_key=api_key)
    except Exception as e:
        raise click.ClickException(str(e)) from None


def _echo_login_success(user_info: dict) -> None:
    click.echo(
        PROMPT_PREFIX
        + "Login successfully. Hi, "
        + click.style(user_info["username"], bold=True)
        + "!"
    )


def ensure_login(
    api_key: str | None = None,
    relogin: bool = False,
    save: bool = True,
    show_success_message: bool = False,
) -> dict:
    """
    进行登录检查
    优先使用传入的 api_key, 其次使用本地保存的 api_key, 如果都没有则手动输入
    """
    config_path = settings.config_path
    http_client = HttpClient()
    prompted_for_api_key = False

    if not relogin and not api_key:
        existing_key = get_saved_api_key()
        if existing_key:
            user_info = _check_api_key(http_client, existing_key)
            if user_info:
                if save:
                    _save_config(config_path, user_info)
                return user_info
            click.echo(PROMPT_PREFIX + "Saved API key is invalid. Please log in again.")

    resolved_api_key = str(api_key).strip() if api_key else _prompt_api_key()
    prompted_for_api_key = not api_key
    if not resolved_api_key:
        raise click.ClickException(PROMPT_PREFIX + "API key cannot be empty")

    user_info = _check_api_key(http_client, resolved_api_key)
    if not user_info:
        click.echo(PROMPT_PREFIX + "Login failed, invalid API key")
        exit(1)

    if save:
        _save_config(config_path, user_info)
    if show_success_message and prompted_for_api_key:
        _echo_login_success(user_info)
    return user_info


@click.option(
    "-k",
    "--api-key",
    type=str,
    help="API Key for authentication",
)
@click.option(
    "-r",
    "--relogin",
    is_flag=True,
    help="Force re-login and overwrite the local API Key",
)
def login(api_key: str | None, relogin: bool):
    """Login to the Trio service"""
    if not relogin and not api_key:
        existing_key = get_saved_api_key()
        if existing_key:
            user_info = _check_api_key(HttpClient(), existing_key)
            if user_info:
                click.echo(
                    PROMPT_PREFIX
                    + "You are already logged in. Use `"
                    + click.style("trio login --relogin", bold=True)
                    + "` to force relogin."
                )
                return

    user_info = ensure_login(api_key=api_key, relogin=relogin, save=True)
    _echo_login_success(user_info)


def logout():
    """Logout from the Trio service"""
    config_path = settings.config_path
    if config_path.exists():
        prompt = (
            PROMPT_PREFIX
            + "Are you sure you want to logout?"
            + click.style(" (y/N):", bold=True)
        )
        if not click.confirm(
            prompt,
            default=False,
            show_default=False,
            prompt_suffix=" ",
        ):
            click.echo(PROMPT_PREFIX + "Logout cancelled.")
            return

        try:
            config_path.unlink()
        except Exception as e:
            raise click.ClickException(f"Failed to delete config file: {e}") from None
        settings.api_key = ""
        click.echo(
            PROMPT_PREFIX
            + "Logout successfully. You can use `"
            + click.style("trio login", bold=True)
            + "` to login again."
        )
        return

    click.echo(
        PROMPT_PREFIX
        + "You are not logged in. If you want to login in, please use `"
        + click.style("trio login", bold=True)
        + "` to login."
    )
