import base64
import json

import typer
from urllib.parse import urlsplit, urlunsplit

from safety.tool.constants import (
    NPMJS_PUBLIC_REPOSITORY_URL,
    PYPI_PUBLIC_REPOSITORY_URL,
)
from typing import Optional, Literal


def index_credentials(ctx: typer.Context) -> str:
    """
    Returns the index credentials for the current context.
    This should be used together with user:index_credential for index
    basic auth.

    Args:
        ctx (typer.Context): The context.

    Returns:
        str: The index credentials.
    """
    api_key = None
    token = None

    if auth := getattr(ctx.obj, "auth", None):
        client = auth.client
        token = client.token.get("access_token") if client.token else None
        api_key = client.api_key

    auth_envelop = json.dumps(
        {
            "version": "1.0",
            "access_token": token,
            "api_key": api_key,
            "project_id": ctx.obj.project.id if ctx.obj.project else None,
        }
    )
    return base64.urlsafe_b64encode(auth_envelop.encode("utf-8")).decode("utf-8")


def build_index_url(
    ctx: typer.Context, index_url: Optional[str], index_type: Literal["pypi", "npm"]
) -> str:
    """
    Builds the index URL for the current context.
    """
    if index_url is None:
        # TODO: Make this to select the index based on auth org or project
        index_url = {
            "pypi": PYPI_PUBLIC_REPOSITORY_URL,
            "npm": NPMJS_PUBLIC_REPOSITORY_URL,
        }[index_type]

    url = urlsplit(index_url)

    encoded_auth = index_credentials(ctx)
    netloc = f"user:{encoded_auth}@{url.netloc}"

    if type(url.netloc) is bytes:
        url = url._replace(netloc=netloc.encode("utf-8"))
    elif type(url.netloc) is str:
        url = url._replace(netloc=netloc)

    return urlunsplit(url)
