"""Workspace commands for manta-client CLI."""

from __future__ import annotations

import asyncio
import re
from typing import Any

import typer

from manta_client.api.agent.cluster import get_cluster_api
from manta_client.api.agent.workspace import get_workspace_api
from manta_client.api.client import APIError
from manta_client.exitcodes import exit_code_for_api_error
from manta_client.output import (
    console,
    is_quiet,
    print_error,
    print_json,
    print_key_value,
    print_success,
    print_table,
)

app = typer.Typer(help="Workspace management")


def _parse_repo(repo_str: str) -> dict[str, Any]:
    """Parse repo string in format: url[@branch][:/path]

    Examples:
        https://github.com/org/repo
        https://github.com/org/repo@main
        https://github.com/org/repo@dev:/custom/path
        https://github.com/org/repo:/custom/path
    """
    result: dict[str, Any] = {}

    # Extract path part first (after :/)
    path_match = re.search(r":(/[^/]\S*)$", repo_str)
    if path_match:
        result["path"] = path_match.group(1)
        repo_str = repo_str[: path_match.start()]

    # Extract branch (after @)
    if "@" in repo_str:
        url, branch = repo_str.rsplit("@", 1)
        result["url"] = url
        result["branch"] = branch
    else:
        result["url"] = repo_str

    return result


async def _resolve_cluster_id(cluster_name: str) -> int:
    """Resolve cluster name to ID."""
    api = get_cluster_api()
    cluster = await api.get_cluster_by_name(cluster_name)
    cluster_id = cluster.get("id")
    if not cluster_id:
        raise ValueError(f"Cluster '{cluster_name}' not found")
    return cluster_id


async def _resolve_workspace_id(workspace_name: str) -> int:
    """Resolve workspace name to ID."""
    api = get_workspace_api()
    workspace = await api.get_workspace_by_name(workspace_name)
    workspace_id = workspace.get("id")
    if not workspace_id:
        raise ValueError(f"Workspace '{workspace_name}' not found")
    return workspace_id


@app.command("create")
def create_workspace(
    name: str = typer.Option(..., "--name", "-n", help="Workspace name"),
    cluster: str = typer.Option(None, "--cluster", "-c", help="Cluster name"),
    repos: list[str] | None = typer.Option(  # noqa: B008
        None,
        "--repo",
        "-r",
        help="Git repo (url[@branch][:/path])",
    ),
    description: str = typer.Option(None, "--description", "-d", help="Description"),
    json_output: bool = typer.Option(False, "--json", "-j", help="Output as JSON"),
) -> None:
    """Create a new workspace.

    Examples:
        manta-client workspace create -n "milvus-idc" --cluster idc \\
          -r "https://github.com/milvus-io/milvus" \\
          -r "https://github.com/milvus-io/pymilvus@2.5"
    """

    async def _create():
        data: dict[str, Any] = {"name": name}
        if description:
            data["description"] = description
        if cluster:
            data["cluster_id"] = await _resolve_cluster_id(cluster)
        if repos:
            data["repos"] = [_parse_repo(r) for r in repos]

        api = get_workspace_api()
        return await api.create_workspace(data)

    try:
        result = asyncio.run(_create())
    except APIError as e:
        print_error(e.message)
        raise typer.Exit(exit_code_for_api_error(e.code)) from None
    except ValueError as e:
        print_error(str(e))
        raise typer.Exit(exit_code_for_api_error(e.code)) from None

    if json_output:
        print_json(result)
    elif is_quiet():
        print(result.get("name", ""))
    else:
        print_success(f"Workspace created: {result.get('name')}")
        status = result.get("status", "")
        console.print(f"Status: {status}")
        if result.get("namespace"):
            console.print(f"Namespace: {result.get('namespace')}")


@app.command("list")
def list_workspaces(
    json_output: bool = typer.Option(False, "--json", "-j", help="Output as JSON"),
) -> None:
    """List your workspaces."""

    async def _list():
        api = get_workspace_api()
        return await api.list_workspaces()

    try:
        result = asyncio.run(_list())
    except APIError as e:
        print_error(e.message)
        raise typer.Exit(exit_code_for_api_error(e.code)) from None

    items = result.get("items", [])
    total = result.get("total", 0)

    if json_output:
        print_json(result)
        return

    if not items:
        if not is_quiet():
            console.print("[dim]No workspaces found.[/dim]")
        return

    if is_quiet():
        for item in items:
            print(item.get("name", ""))
        return

    # Add repo count for display
    for item in items:
        repos = item.get("repos") or []
        item["_repo_count"] = str(len(repos))

    columns = [
        ("id", "ID"),
        ("name", "Name"),
        ("cluster_name", "Cluster"),
        ("_repo_count", "Repos"),
        ("status", "Status"),
        ("created_time", "Created"),
    ]
    print_table(items, columns=columns, title=f"Workspaces ({total})")


@app.command("info")
def workspace_info(
    name: str = typer.Argument(..., help="Workspace name"),
    json_output: bool = typer.Option(False, "--json", "-j", help="Output as JSON"),
) -> None:
    """Show workspace details by name."""

    async def _get():
        api = get_workspace_api()
        return await api.get_workspace_by_name(name)

    try:
        ws = asyncio.run(_get())
    except APIError as e:
        print_error(e.message)
        raise typer.Exit(exit_code_for_api_error(e.code)) from None

    if json_output:
        print_json(ws)
        return

    data: dict[str, Any] = {
        "ID": ws.get("id"),
        "Name": ws.get("name"),
        "Cluster": ws.get("cluster_name") or "-",
        "Namespace": ws.get("namespace") or "-",
        "Status": ws.get("status"),
        "Description": ws.get("description") or "-",
    }
    print_key_value(data, title="Workspace Details")

    repos = ws.get("repos") or []
    if repos:
        console.print("\n[bold]Repos:[/bold]")
        for r in repos:
            url = r.get("url", "")
            branch = r.get("branch")
            path = r.get("path")
            line = f"  - {url}"
            if branch:
                line += f" @ {branch}"
            if path:
                line += f" -> {path}"
            console.print(line)


@app.command("update")
def update_workspace(
    name: str = typer.Argument(..., help="Workspace name"),
    repos: list[str] | None = typer.Option(  # noqa: B008
        None,
        "--repo",
        "-r",
        help="Git repo (url[@branch][:/path]), replaces all repos",
    ),
    description: str = typer.Option(None, "--description", "-d", help="Description"),
    cluster: str = typer.Option(None, "--cluster", "-c", help="Cluster name"),
    json_output: bool = typer.Option(False, "--json", "-j", help="Output as JSON"),
) -> None:
    """Update a workspace by name."""

    async def _update():
        workspace_id = await _resolve_workspace_id(name)
        data: dict[str, Any] = {}
        if description is not None:
            data["description"] = description
        if cluster is not None:
            data["cluster_id"] = await _resolve_cluster_id(cluster)
        if repos is not None:
            data["repos"] = [_parse_repo(r) for r in repos]

        api = get_workspace_api()
        return await api.update_workspace(workspace_id, data)

    try:
        result = asyncio.run(_update())
    except APIError as e:
        print_error(e.message)
        raise typer.Exit(exit_code_for_api_error(e.code)) from None
    except ValueError as e:
        print_error(str(e))
        raise typer.Exit(exit_code_for_api_error(e.code)) from None

    if json_output:
        print_json(result)
    elif is_quiet():
        print(result.get("name", ""))
    else:
        print_success(f"Workspace updated: {result.get('name')}")


@app.command("sync")
def sync_workspace(
    name: str = typer.Argument(..., help="Workspace name"),
    json_output: bool = typer.Option(False, "--json", "-j", help="Output as JSON"),
) -> None:
    """Trigger workspace repo sync to PVC."""

    async def _sync():
        workspace_id = await _resolve_workspace_id(name)
        api = get_workspace_api()
        return await api.sync_workspace(workspace_id)

    try:
        result = asyncio.run(_sync())
    except APIError as e:
        print_error(e.message)
        raise typer.Exit(exit_code_for_api_error(e.code)) from None
    except ValueError as e:
        print_error(str(e))
        raise typer.Exit(exit_code_for_api_error(e.code)) from None

    if json_output:
        print_json(result)
    elif is_quiet():
        print(result.get("sync_job", ""))
    else:
        sync_job = result.get("sync_job", "")
        print_success(f"Sync triggered for workspace '{name}' (job: {sync_job})")


@app.command("delete")
def delete_workspace(
    name: str = typer.Argument(..., help="Workspace name"),
) -> None:
    """Delete a workspace by name."""

    async def _delete():
        workspace_id = await _resolve_workspace_id(name)
        api = get_workspace_api()
        return await api.delete_workspace(workspace_id)

    try:
        asyncio.run(_delete())
        if is_quiet():
            print("deleted")
        else:
            print_success(f"Workspace '{name}' deleted.")
    except APIError as e:
        print_error(e.message)
        raise typer.Exit(exit_code_for_api_error(e.code)) from None
    except ValueError as e:
        print_error(str(e))
        raise typer.Exit(exit_code_for_api_error(e.code)) from None
