import builtins
import logging
from collections.abc import Sequence
from typing import Optional
from uuid import UUID

from radicli import Arg
from wasabi import msg

from prodigy_teams_pam_sdk.errors import CodingTaskNotFound
from prodigy_teams_pam_sdk.models import (
    CodingTaskCreating,
    CodingTaskDetail,
    CodingTaskSummary,
    CodingTaskUpdating,
)

from ..cli import cli
from ..errors import CLIError
from ..messages import Messages
from ..query import resolve_coding_task
from ..ui import print_info_table, print_mutation_result, print_table_with_select
from ._state import get_auth_state

logger = logging.getLogger(__name__)


@cli.subcommand(
    "coding-tasks",
    "list",
    # fmt: off
    select=Arg(
        "--select",
        help=Messages.select.format(opts=builtins.list(CodingTaskSummary.model_fields)),
    ),
    project_id=Arg("--project", help=Messages.filter_by.format(filter="project")),
    status=Arg("--status", help=Messages.filter_by.format(filter="status")),
    as_json=Arg("--json", help=Messages.as_json),
    # fmt: on
)
def list(
    select: builtins.list[str] = ["id", "project_id", "status", "description"],
    project_id: Optional[UUID] = None,
    status: Optional[str] = None,
    as_json: bool = False,
) -> Sequence[CodingTaskSummary]:
    """List coding tasks"""
    client = get_auth_state().client
    items = builtins.list(client.coding_task.all(project_id=project_id, status=status))
    print_table_with_select(items, select=select, as_json=as_json)
    return items


@cli.subcommand(
    "coding-tasks",
    "info",
    id=Arg(help="ID of the coding task"),
    select=Arg(
        "--select",
        help=Messages.select.format(opts=builtins.list(CodingTaskDetail.model_fields)),
    ),
    as_json=Arg("--json", help=Messages.as_json),
)
def info(
    id: UUID,
    select: Optional[builtins.list[str]] = None,
    as_json: bool = False,
) -> CodingTaskDetail:
    """Get detailed info for an coding task"""
    res = resolve_coding_task(id)
    print_info_table(res, as_json=as_json, select=select)
    return res


@cli.subcommand(
    "coding-tasks",
    "pull",
    # fmt: off
    project_id=Arg("--project", help=Messages.filter_by.format(filter="project")),
    as_json=Arg("--json", help=Messages.as_json),
    # fmt: on
)
def pull(
    project_id: Optional[UUID] = None,
    as_json: bool = False,
) -> Sequence[CodingTaskDetail]:
    """Pull planned coding tasks and mark them as in-progress"""
    client = get_auth_state().client
    kwargs: dict = {"status": "planned"}
    if project_id is not None:
        kwargs["project_id"] = project_id
    planned = builtins.list(client.coding_task.all(**kwargs))
    results: builtins.list[CodingTaskDetail] = []
    for task in planned:
        body = CodingTaskUpdating(id=task.id, status="in_progress")
        updated = client.coding_task.update(body)
        results.append(updated)
    if not results:
        if not as_json:
            msg.info("No planned coding tasks found")
        else:
            print_table_with_select([], select=[], as_json=True)
        return results
    select = [
        "id",
        "project_id",
        "description",
        "context_summary",
        "conversation_id",
        "status",
    ]
    print_table_with_select(results, select=select, as_json=as_json)
    return results


@cli.subcommand(
    "coding-tasks",
    "create",
    # fmt: off
    project_id=Arg("--project", help=Messages.project_id.format(noun="coding task")),
    description=Arg(
        "--description", help=Messages.description.format(noun="coding task")
    ),
    context_summary=Arg("--context", help="Context summary for the coding task"),
    conversation_id=Arg(
        "--conversation", help="Conversation ID to associate with the coding task"
    ),
    as_json=Arg("--json", help=Messages.as_json),
    # fmt: on
)
def create(
    project_id: UUID,
    description: str,
    context_summary: Optional[str] = None,
    conversation_id: Optional[UUID] = None,
    as_json: bool = False,
) -> UUID:
    """Create a new coding task"""
    auth = get_auth_state()
    client = auth.client
    # Get current user ID from the API token's JWT payload
    api_token = auth.get_api_token()
    user_id = UUID(api_token.header["uid"])
    body = CodingTaskCreating(
        project_id=project_id,
        description=description,
        context_summary=context_summary or "",
        conversation_id=conversation_id,
        creator_id=user_id,
    )
    res = client.coding_task.create(body)
    print_mutation_result(
        {"id": str(res.id), "project_id": str(res.project_id)},
        Messages.T002.format(noun="coding task", name=res.id),
        as_json=as_json,
    )
    if not as_json:
        print_info_table(res)
    return res.id


@cli.subcommand(
    "coding-tasks",
    "latest",
    as_json=Arg("--json", help=Messages.as_json),
)
def latest(
    as_json: bool = False,
) -> Optional[CodingTaskSummary]:
    """Get the most recently updated non-done coding task."""
    client = get_auth_state().client
    items = builtins.list(client.coding_task.all())
    active = [t for t in items if t.status in ("planned", "in_progress")]
    if not active:
        if as_json:
            print("{}")
        else:
            msg.info("No active coding tasks")
        return None
    best = max(active, key=lambda t: t.updated)
    print_info_table(best, as_json=as_json)
    return best


@cli.subcommand(
    "coding-tasks",
    "context",
    id=Arg(help="ID of the coding task"),
    as_json=Arg("--json", help=Messages.as_json),
)
def context(
    id: UUID,
    as_json: bool = False,
) -> Sequence[dict]:
    """Fetch conversation messages for a task's linked conversation."""
    task = resolve_coding_task(id)
    if not task.conversation_id:
        if as_json:
            print("[]")
        else:
            msg.info("No conversation linked to this task")
        return []
    client = get_auth_state().client
    items = builtins.list(
        client.conversation_message.all(conversation_id=task.conversation_id)
    )
    results = [{"role": m.role, "content": m.content} for m in items]
    if as_json:
        import json

        print(json.dumps(results, indent=2))
    else:
        for m in results:
            role_label = "User" if m["role"] == "user" else "Assistant"
            msg.divider(role_label)
            print(m["content"])
    return results


@cli.subcommand(
    "coding-tasks",
    "update",
    # fmt: off
    id=Arg(help="ID of the coding task"),
    status=Arg("--status", help="New status (planned, in_progress, done, cancelled)"),
    description=Arg("--description", help="New description for the coding task"),
    resolution=Arg(
        "--resolution",
        help="What was done (or why nothing was done). Set when closing a task.",
    ),
    as_json=Arg("--json", help=Messages.as_json),
    # fmt: on
)
def update(
    id: UUID,
    status: Optional[str] = None,
    description: Optional[str] = None,
    resolution: Optional[str] = None,
    as_json: bool = False,
) -> CodingTaskDetail:
    """Update a coding task"""
    auth = get_auth_state()
    body = CodingTaskUpdating(
        id=id,
        status=status,
        description=description,
        resolution=resolution,
    )
    res = auth.client.coding_task.update(body)
    print_mutation_result(
        {"id": str(res.id), "status": res.status},
        Messages.T051.format(noun="coding task", name=res.id),
        as_json=as_json,
    )
    if not as_json:
        print_info_table(res)
    return res


@cli.subcommand(
    "coding-tasks",
    "delete",
    id=Arg(help="ID of the coding task"),
    as_json=Arg("--json", help=Messages.as_json),
)
def delete(id: UUID, as_json: bool = False) -> UUID:
    """Delete a coding task"""
    auth = get_auth_state()
    try:
        auth.client.coding_task.delete(id=id)
    except CodingTaskNotFound:
        raise CLIError(Messages.E006.format(noun="coding task", name=id))
    print_mutation_result(
        {"id": str(id)},
        Messages.T003.format(noun="coding task", name=id),
        as_json=as_json,
    )
    return id
