import builtins
import json
from collections.abc import Sequence
from typing import Optional, Union
from uuid import UUID

from radicli.util import Arg
from wasabi import msg

from prodigy_teams_pam_sdk.models import AssetCreating, AssetDetail, AssetSummary

from ..cli import cli
from ..errors import CLIError, ProdigyTeamsErrors
from ..messages import Messages
from ..query import resolve_asset, resolve_asset_id
from ..ui import print_info_table, print_mutation_result, print_table_with_select
from ..util import resolve_remote_path
from ._state import get_auth_state


@cli.subcommand(
    "assets",
    "list",
    # fmt: off
    select=Arg(
        "--select",
        help=Messages.select.format(opts=builtins.list(AssetSummary.model_fields)),
    ),
    as_json=Arg("--json", help=Messages.as_json),
    # fmt: on
)
def list(
    select: builtins.list[str] = ["id", "name", "kind"], as_json: bool = False
) -> Sequence[AssetSummary]:
    """List all assets on the cluster registered with Ellf"""
    client = get_auth_state().client
    items = builtins.list(client.asset.all())
    print_table_with_select(items, select=select, as_json=as_json)
    return items


@cli.subcommand(
    "assets",
    "info",
    name_or_id=Arg(help=Messages.name_or_id.format(noun="asset")),
    project_id=Arg(help=Messages.project_id.format(noun="asset")),
    cluster_id=Arg(help=Messages.cluster_id.format(noun="asset")),
    select=Arg(
        "--select",
        help=Messages.select.format(opts=builtins.list(AssetDetail.model_fields)),
    ),
    as_json=Arg("--json", help=Messages.as_json),
)
def info(
    name_or_id: Union[str, UUID],
    project_id: Optional[UUID] = None,
    cluster_id: Optional[UUID] = None,
    select: Optional[builtins.list[str]] = None,
    as_json: bool = False,
) -> AssetDetail:
    """
    Get detailed info for an asset uploaded to the cluster and registered
    with Ellf
    """
    res = resolve_asset(name_or_id, broker_id=cluster_id, project_id=project_id)
    print_info_table(res, as_json=as_json, select=select)
    return res


@cli.subcommand(
    "assets",
    "create",
    name=Arg(help=Messages.name.format(noun="asset")),
    kind=Arg("--kind", help=Messages.asset_kind),
    path=Arg(help=Messages.path.format(noun="asset")),
    version=Arg("--version", help=Messages.version.format(noun="asset")),
    meta=Arg("--meta", help=Messages.asset_meta),
    exists_ok=Arg("--exists-ok", help=Messages.exists_ok),
    as_json=Arg("--json", help=Messages.as_json),
)
def create(
    kind: str,
    name: str,
    path: str,
    version: str = "0.0.0",
    meta: str = "{}",
    exists_ok: bool = False,
    as_json: bool = False,
) -> UUID | None:
    """
    Create an asset on the cluster and register it with Ellf. Assets
    point to files or directories you control. The Ellf server only has
    a reference to them. This command doesn't transfer any data. See `ptc files`
    for utilities to transfer files to and from your cluster
    """
    try:
        _ = json.loads(meta)
    except json.JSONDecodeError:
        raise CLIError(Messages.E121, str(meta))
    auth = get_auth_state()
    client = auth.client
    resolved_path = resolve_remote_path(client, path, auth.broker_host)
    try:
        asset = client.asset.create(
            AssetCreating(
                broker_id=auth.broker_id,
                name=name,
                kind=kind,
                version=version,
                meta=json.loads(meta),
                path=resolved_path,
            )
        )
    except ProdigyTeamsErrors.AssetExists:
        if exists_ok:
            msg.info(Messages.T001.format(noun="asset", name=name))
            return None
        raise CLIError(Messages.E002.format(noun="asset", name=name))
    assert asset.path is not None
    print_mutation_result(
        {"id": str(asset.id), "name": asset.name},
        Messages.T002.format(noun="asset", name=asset.name),
        as_json=as_json,
    )
    return asset.id


@cli.subcommand(
    "assets",
    "delete",
    name_or_id=Arg(help=Messages.name_or_id.format(noun="asset")),
    project_id=Arg(help=Messages.project_id.format(noun="asset")),
    cluster_id=Arg(help=Messages.cluster_id.format(noun="asset")),
    as_json=Arg("--json", help=Messages.as_json),
)
def delete(
    name_or_id: Union[str, UUID],
    cluster_id: Optional[UUID] = None,
    project_id: Optional[UUID] = None,
    as_json: bool = False,
) -> UUID:
    """Delete an asset registered with Ellf"""
    asset_id = resolve_asset_id(name_or_id, broker_id=cluster_id, project_id=project_id)
    auth = get_auth_state()
    try:
        auth.client.asset.delete(id=asset_id)
    except ProdigyTeamsErrors.AssetNotFound:
        raise CLIError(Messages.E006.format(noun="asset", name=name_or_id))
    except ProdigyTeamsErrors.AssetForbiddenDelete:
        raise CLIError(Messages.E007.format(noun="asset", name=name_or_id))
    else:
        print_mutation_result(
            {"id": str(asset_id), "deleted": True},
            Messages.T003.format(noun="asset", name=name_or_id),
            as_json=as_json,
        )
    return asset_id
