"""
Auth command - Authenticate with ToRivers.

This module provides authentication functionality for the ToRivers
developer platform.
"""

from __future__ import annotations

import json
import os
import webbrowser
from datetime import datetime, timezone
from pathlib import Path
from typing import Any

import httpx
from rich.console import Console
from rich.panel import Panel
from rich.prompt import Confirm, Prompt

from ._config import (
    API_TIMEOUT_SECONDS,
    extract_error_message,
    get_api_base_url,
    get_auth_url,
    get_config_path,
    is_authenticated,
    read_config,
)

console = Console()


def login() -> bool:
    """
    Authenticate with ToRivers.

    Opens a browser for sign-in and stores a validated access token locally.

    Returns:
        True if authentication successful, False otherwise
    """
    console.print(
        Panel.fit(
            "[bold]ToRivers Developer Authentication[/bold]",
            subtitle="Authenticate to submit automations",
        )
    )
    console.print()

    # Check if already authenticated
    api_base_url = get_api_base_url()
    existing_token = _get_stored_token()
    if existing_token:
        existing_profile, error_message = _fetch_developer_profile(
            existing_token, api_base_url
        )
        if existing_profile is not None:
            console.print(
                f"[green]Already authenticated as:[/green] "
                f"{existing_profile.get('email', 'Unknown')}"
            )
            if not Confirm.ask("Would you like to re-authenticate?", default=False):
                return True
        elif error_message:
            console.print(
                "[yellow]Stored token is not valid anymore.[/yellow] "
                f"{error_message}"
            )

    auth_url = get_auth_url()
    console.print("[dim]Opening browser for authentication...[/dim]")
    console.print()

    try:
        webbrowser.open(auth_url)
        console.print("[dim]Browser opened. Complete authentication there.[/dim]")
    except Exception:
        console.print("[dim]Please open this URL in your browser:[/dim]")
        console.print(f"[cyan]{auth_url}[/cyan]")

    console.print()
    console.print(
        "[dim]Copy the access token from the browser and paste it below.[/dim]"
    )

    token = Prompt.ask(
        "Access token",
        default="",
        show_default=False,
    ).strip()

    if not token:
        console.print("[red]Error:[/red] Access token is required")
        return False

    profile, error_message = _fetch_developer_profile(token, api_base_url)
    if profile is None:
        console.print(
            f"[red]Error:[/red] Unable to validate token. {error_message or ''}".strip()
        )
        return False

    if not _store_token(token, profile, api_base_url):
        console.print("[red]Error:[/red] Failed to store token")
        return False

    console.print()
    console.print(
        Panel.fit(
            f"[green]✓ Authentication successful![/green]\n\n"
            f"Logged in as: [cyan]{profile.get('email', 'Developer')}[/cyan]\n\n"
            "You can now submit automations for review.",
            title="Login Complete",
        )
    )

    return True


def logout() -> bool:
    """
    Log out from ToRivers.

    Removes stored authentication tokens.

    Returns:
        True if successful, False otherwise
    """
    config_path = get_config_path()

    if not config_path.exists():
        console.print("[dim]Not currently logged in[/dim]")
        return True

    try:
        # Remove the config file
        config_path.unlink()
        console.print("[green]Successfully logged out[/green]")
        return True
    except Exception as e:
        console.print(f"[red]Error logging out:[/red] {e}")
        return False


def whoami() -> None:
    """Show current authentication status."""
    if not is_authenticated():
        console.print("[yellow]Not authenticated[/yellow]")
        console.print("[dim]Run 'torivers login' to authenticate[/dim]")
        return

    token = _get_stored_token()
    if not token:
        console.print("[yellow]Not authenticated[/yellow]")
        console.print("[dim]Run 'torivers login' to authenticate[/dim]")
        return

    api_base_url = get_api_base_url()
    profile, error_message = _fetch_developer_profile(token, api_base_url)
    if profile is None:
        console.print("[yellow]Stored token is invalid or expired.[/yellow]")
        if error_message:
            console.print(f"[dim]{error_message}[/dim]")
        console.print("[dim]Run 'torivers login' to authenticate again.[/dim]")
        return

    # Keep stored profile in sync with platform.
    _store_token(token, profile, api_base_url)

    console.print(
        Panel.fit(
            f"[bold]Current User[/bold]\n\n"
            f"Email: [cyan]{profile.get('email', 'Unknown')}[/cyan]\n"
            f"Developer ID: [dim]{profile.get('id', 'Unknown')}[/dim]\n"
            f"Developer Mode: [green]{'Yes' if profile.get('is_developer') else 'No'}[/green]\n"
            f"Authenticated: [green]Yes[/green]",
            title="Authentication Status",
        )
    )


def _get_stored_token() -> str | None:
    token = read_config().get("auth_token")
    if isinstance(token, str) and token.strip():
        return token.strip()
    return None


def _fetch_developer_profile(
    token: str, api_base_url: str
) -> tuple[dict[str, Any] | None, str | None]:
    headers = {"Authorization": f"Bearer {token}"}
    try:
        with httpx.Client(timeout=API_TIMEOUT_SECONDS) as client:
            response = client.get(f"{api_base_url}/developer/me", headers=headers)
    except httpx.TimeoutException:
        return None, "Request timed out while validating token."
    except httpx.HTTPError as exc:
        return None, f"Failed to connect to API: {exc}"

    if response.status_code == 401:
        return None, "Invalid or expired token."
    if response.status_code == 403:
        return None, "Developer mode is not enabled for this account."
    if response.status_code != 200:
        return None, extract_error_message(response)

    payload = response.json() if response.content else {}
    if not isinstance(payload, dict):
        return None, "Unexpected profile response from API."

    user_id = payload.get("id")
    if not isinstance(user_id, str) or not user_id:
        return None, "Profile response did not include a valid user ID."

    return payload, None


def _store_token(token: str, profile: dict[str, Any], api_base_url: str) -> bool:
    """Store the authentication token securely."""
    try:
        config_dir = Path.home() / ".torivers"
        config_dir.mkdir(parents=True, exist_ok=True)

        config_path = config_dir / "config.json"

        config: dict[str, Any] = {}
        if config_path.exists():
            try:
                with open(config_path) as f:
                    data = json.load(f)
                if isinstance(data, dict):
                    config = data
            except (json.JSONDecodeError, OSError):
                config = {}

        config["auth_token"] = token
        config["authenticated_at"] = datetime.now(timezone.utc).isoformat()
        config["api_base_url"] = api_base_url
        config["user"] = {
            "email": profile.get("email"),
            "developer_id": profile.get("id"),
            "full_name": profile.get("full_name"),
        }

        # Save config with restricted permissions
        with open(config_path, "w") as f:
            json.dump(config, f, indent=2)

        # Set file permissions (Unix only)
        try:
            os.chmod(config_path, 0o600)
        except (OSError, AttributeError):
            pass  # Ignore on Windows

        return True

    except Exception as e:
        console.print(f"[red]Error storing token:[/red] {e}")
        return False
