"""Interactive API key generation for Neuracore authentication.

This module provides functionality for generating API keys through interactive
user authentication. It prompts for email and password credentials, obtains
an access token, and creates a new API key for CLI usage.
"""

from getpass import getpass  # For hidden password input

import requests
from pydantic import BaseModel, ValidationError

from neuracore.core.cli.get_user_confirmation import get_user_confirmation
from neuracore.core.config.config_manager import get_config_manager
from neuracore.core.exceptions import AuthenticationError, InputError

from ..const import API_URL, MAX_INPUT_ATTEMPTS


class APIKey(BaseModel):
    """API key model."""

    key: str


class Token(BaseModel):
    """OAuth2 token response model."""

    access_token: str
    token_type: str


def generate_api_key() -> str:
    """Generate a new API key through interactive user authentication.

    Prompts the user for their registered email and password, authenticates
    with the Neuracore server to obtain an access token, then uses that token
    to create a new API key for programmatic access. The process is interactive
    and handles authentication securely by hiding password input.

    Returns:
        The generated API key string if successful, None if authentication
        or API key generation fails.

    Raises:
        AuthenticationError: If API key verification fails due to invalid
            credentials, network issues, or server errors.
        InputError: If there is an issue with the user's input
    """
    # Prompt the user for credentials
    access_token = None
    for i in range(MAX_INPUT_ATTEMPTS):
        try:
            email = input("Enter your registered email: ")
            password = getpass("Enter your password: ")
            auth_response = requests.post(
                f"{API_URL}/auth/token",
                headers={"Content-Type": "application/x-www-form-urlencoded"},
                data={"username": email, "password": password},
            )
            if auth_response.status_code == 401 and i + 1 < MAX_INPUT_ATTEMPTS:
                print("Incorrect email or password.")

                again = get_user_confirmation("Do you wish to try again?")
                if again:
                    continue
                else:
                    raise InputError("Invalid Email or Password")

            auth_response.raise_for_status()
            token_data = Token.model_validate(auth_response.json())
            access_token = token_data.access_token
            break
        except ValidationError:
            raise AuthenticationError("Invalid token from server")
        except requests.exceptions.RequestException as e:
            raise AuthenticationError(f"Failed to get Auth Token: {e}")

    if not access_token:
        print("Too many failed attempts, perhaps check your Caps Lock?")
        raise InputError("Out of attempts")

    # Use the access token to request an API key
    try:
        headers = {"Authorization": f"Bearer {access_token}"}
        api_key_response = requests.post(
            f"{API_URL}/auth/api-key",
            headers=headers,
        )
        api_key_response.raise_for_status()
        api_key = APIKey.model_validate(api_key_response.json()).key
        print(f"Your new API key is: {api_key}")
        config_manager = get_config_manager()
        config_manager.config.api_key = api_key
        config_manager.save_config()
        return api_key
    except ValidationError:
        raise AuthenticationError("Invalid api-key from server")
    except requests.exceptions.RequestException as e:
        raise AuthenticationError(f"Failed to create API key: {e}")


if __name__ == "__main__":
    generate_api_key()
