"""Authenticated Paracord API client."""

from pathlib import Path
from typing import TYPE_CHECKING

import httpx
import typer

from paracord.auth.config import (
    get_current_environment,
    get_environment_config,
    get_org_for_path,
    get_org_credentials,
    get_authenticated_orgs,
    set_org_for_path,
    get_user_email,
)
from paracord.utils.console import console, print_warning


class AuthenticationError(Exception):
    """Raised when not authenticated or token is invalid."""

    pass


def interactive_org_picker(orgs: dict, env: str) -> str | None:
    """Interactively pick an organization from the list.

    Returns the selected org_id or None if cancelled.
    """
    if not orgs:
        return None

    org_list = [(org_id, creds["name"]) for org_id, creds in orgs.items()]

    console.print("\n[bold]Select an organization for this directory:[/bold]\n")

    for i, (org_id, name) in enumerate(org_list, 1):
        console.print(f"  [cyan]{i}[/cyan]. {name}")

    console.print(f"  [dim]0[/dim]. Cancel\n")

    try:
        choice = typer.prompt("Enter number", type=int, default=1)

        if choice == 0:
            return None

        if 1 <= choice <= len(org_list):
            return org_list[choice - 1][0]  # Return org_id

        return None
    except (KeyboardInterrupt, typer.Abort):
        return None


def get_credentials_for_cwd() -> tuple[str, str, str] | None:
    """Get credentials based on the current working directory.

    This function:
    1. Checks if there's a path-based org mapping for cwd
    2. If not, prompts interactively to pick from authenticated orgs
    3. Saves the selection for the directory

    Returns:
        Tuple of (token, org_id, org_name) or None if not authenticated/cancelled
    """
    env = get_current_environment()
    cwd = Path.cwd()

    # Check for existing path mapping
    org_id = get_org_for_path(cwd)

    if org_id:
        org_creds = get_org_credentials(env, org_id)
        if org_creds:
            return (org_creds["token"], org_id, org_creds["name"])
        # Org mapping exists but credentials are gone - continue to prompt

    # No mapping - check authenticated orgs
    orgs = get_authenticated_orgs(env)

    if not orgs:
        return None

    # If only one org, use it and save mapping
    if len(orgs) == 1:
        org_id, org_creds = next(iter(orgs.items()))
        set_org_for_path(cwd, org_id)
        return (org_creds["token"], org_id, org_creds["name"])

    # Multiple orgs - prompt to select
    selected_org_id = interactive_org_picker(orgs, env)

    if not selected_org_id:
        return None

    # Save selection and return credentials
    set_org_for_path(cwd, selected_org_id)
    org_creds = get_org_credentials(env, selected_org_id)
    if org_creds:
        return (org_creds["token"], selected_org_id, org_creds["name"])

    return None


class ParacordClient:
    """Authenticated client for Paracord API."""

    def __init__(self):
        credentials = get_credentials_for_cwd()
        if not credentials:
            # Check if any orgs are authenticated at all
            env = get_current_environment()
            orgs = get_authenticated_orgs(env)
            if not orgs:
                raise AuthenticationError(
                    "Not logged in. Run 'paracord login' first."
                )
            else:
                raise AuthenticationError(
                    "No organization selected. Run 'paracord org' to select one."
                )

        self._token, self._org_id, self._org_name = credentials
        self._env_config = get_environment_config()

    @property
    def base_url(self) -> str:
        return self._env_config["api_url"]

    @property
    def org_id(self) -> str:
        return self._org_id

    @property
    def org_name(self) -> str:
        return self._org_name

    @property
    def headers(self) -> dict:
        return {"Authorization": f"Token {self._token}"}

    def get(self, path: str, **kwargs) -> httpx.Response:
        """Make GET request."""
        url = f"{self.base_url}{path}"
        return httpx.get(url, headers=self.headers, **kwargs)

    def post(self, path: str, **kwargs) -> httpx.Response:
        """Make POST request."""
        url = f"{self.base_url}{path}"
        return httpx.post(url, headers=self.headers, **kwargs)

    def patch(self, path: str, **kwargs) -> httpx.Response:
        """Make PATCH request."""
        url = f"{self.base_url}{path}"
        return httpx.patch(url, headers=self.headers, **kwargs)

    def delete(self, path: str, **kwargs) -> httpx.Response:
        """Make DELETE request."""
        url = f"{self.base_url}{path}"
        return httpx.delete(url, headers=self.headers, **kwargs)

    def upload_file(self, path: str, file_path: Path, local_path: str) -> httpx.Response:
        """Upload a file using multipart/form-data."""
        url = f"{self.base_url}{path}"
        with open(file_path, "rb") as f:
            files = {"file": (file_path.name, f)}
            data = {"local_path": local_path}
            return httpx.post(url, headers=self.headers, files=files, data=data, timeout=60.0)
