"""User management commands — list, get, create, update, delete, roles."""
from __future__ import annotations

from typing import Optional

import typer

from dattos_cli.client import ApiError
from dattos_cli.main import get_client, handle_api_error
from dattos_cli.output import is_tty, print_json
from dattos_cli.table import print_record, print_table


def _fmt_blocked(v) -> str:
    return "yes" if v else "—"


USERS_COLUMNS = [
    ("ID",      "Id",           None),
    ("Code",    "UserCode",     None),
    ("Name",    "FullName",     None),
    ("Email",   "EmailAddress", None),
    ("Blocked", "Blocked",      _fmt_blocked),
]

ROLES_COLUMNS = [
    ("ID",          "Id",          None),
    ("Name",        "Name",        None),
    ("Description", "Description", None),
]

USER_ROLES_COLUMNS = [
    ("ID",   "Id",   None),
    ("Name", "Name", None),
]

SESSIONS_COLUMNS = [
    ("User",    "UserName",    None),
    ("IP",      "IpAddress",   None),
    ("Created", "CreatedDate", None),
    ("Token",   "AuthToken",   None),
]

app = typer.Typer(help="Manage Dattos users.", no_args_is_help=True)


@app.command("list")
def users_list(
    search: Optional[str] = typer.Option(None, "--search", "-s", help="Filter by name (partial match)."),
    page_size: int = typer.Option(50, "--page-size", help="Number of results per page."),
    no_cache: bool = typer.Option(False, "--no-cache", help="Bypass cache, fetch fresh data."),
    raw: bool = typer.Option(False, "--raw", help="Output raw JSON."),
):
    """List users in the organization."""
    client = get_client()
    params: dict = {"pageInfo.page": 0, "pageInfo.pageSize": page_size}
    if search:
        params["name"] = search
    try:
        resp = client.get("/api/User", params=params, cache=not no_cache, cache_ttl=300)
        # /api/User returns {"Data": [...], "TotalItems": N} — unwrap for consistent output
        data = resp.get("Data", resp) if isinstance(resp, dict) else resp
        if raw or not is_tty():
            print_json(data)
        else:
            print_table(data, USERS_COLUMNS, label="usuários")
    except ApiError as e:
        handle_api_error(e)


@app.command("get")
def users_get(
    user_id: int = typer.Argument(help="User ID."),
    raw: bool = typer.Option(False, "--raw", help="Output raw JSON."),
):
    """Get a user by ID."""
    client = get_client()
    try:
        data = client.get(f"/api/User/{user_id}")
        if raw or not is_tty():
            print_json(data)
        else:
            print_record(data)
    except ApiError as e:
        handle_api_error(e)


@app.command("roles")
def users_roles(
    user_id: int = typer.Argument(help="User ID."),
    raw: bool = typer.Option(False, "--raw", help="Output raw JSON."),
):
    """Get the Privacy Profiles (roles) assigned to a user."""
    client = get_client()
    try:
        data = client.get(f"/api/User/{user_id}/Roles")
        if raw or not is_tty():
            print_json(data)
        else:
            print_table(data, USER_ROLES_COLUMNS, label="roles")
    except ApiError as e:
        handle_api_error(e)


@app.command("list-roles")
def users_list_roles(
    raw: bool = typer.Option(False, "--raw", help="Output raw JSON."),
):
    """List all available Privacy Profiles (roles) in the organization.
    Use the role IDs with set-roles to assign permissions to users."""
    client = get_client()
    try:
        data = client.get("/api/Role")
        if raw or not is_tty():
            print_json(data)
        else:
            print_table(data, ROLES_COLUMNS, label="roles")
    except ApiError as e:
        handle_api_error(e)


@app.command("create")
def users_create(
    code: str = typer.Option(..., "--code", help="Unique user code (e.g. JDOE). Cannot be changed later."),
    name: str = typer.Option(..., "--name", help="Full name of the user."),
    email: str = typer.Option(..., "--email", help="Email address."),
    culture: str = typer.Option("pt-BR", "--culture", help="UI language (e.g. pt-BR, en-US)."),
    blocked: bool = typer.Option(False, "--blocked/--active", help="Create user as blocked."),
    raw: bool = typer.Option(False, "--raw", help="Output raw JSON."),
):
    """Create a new user in the organization. Dattos will send an invitation email automatically."""
    client = get_client()
    payload = {
        "UserCode": code,
        "FullName": name,
        "EmailAddress": email,
        "Culture": culture,
        "Blocked": blocked,
        "SupportUser": False,
        "Id": 0,
    }
    try:
        data = client.post("/api/User", json=payload)
        if raw or not is_tty():
            print_json(data)
        else:
            print_record(data)
    except ApiError as e:
        handle_api_error(e)


@app.command("update")
def users_update(
    user_id: int = typer.Argument(help="User ID to update."),
    name: Optional[str] = typer.Option(None, "--name", help="New full name."),
    email: Optional[str] = typer.Option(None, "--email", help="New email address."),
    culture: Optional[str] = typer.Option(None, "--culture", help="UI language (e.g. pt-BR, en-US)."),
    blocked: Optional[bool] = typer.Option(None, "--blocked/--active", help="Block or unblock the user."),
    raw: bool = typer.Option(False, "--raw", help="Output raw JSON."),
):
    """Update a user's properties. Only provided fields are changed (read-modify-write)."""
    client = get_client()
    try:
        current = client.get(f"/api/User/{user_id}")
    except ApiError as e:
        handle_api_error(e)
        return
    if name is not None:
        current["FullName"] = name
    if email is not None:
        current["EmailAddress"] = email
    if culture is not None:
        current["Culture"] = culture
    if blocked is not None:
        current["Blocked"] = blocked
    try:
        data = client.put(f"/api/User/{user_id}", json=current)
        if raw or not is_tty():
            print_json(data)
        else:
            print_record(data)
    except ApiError as e:
        handle_api_error(e)


@app.command("delete")
def users_delete(
    user_id: int = typer.Argument(help="User ID to delete."),
    yes: bool = typer.Option(False, "--yes", "-y", help="Confirm deletion without prompt."),
):
    """Delete a user. Requires --yes to confirm (destructive, irreversible)."""
    if not yes:
        typer.echo("Error: deletion requires --yes flag to confirm.", err=True)
        raise typer.Exit(1)
    client = get_client()
    try:
        client.delete(f"/api/User/{user_id}")
        print_json({"status": "deleted", "userId": user_id})
    except ApiError as e:
        handle_api_error(e)


@app.command("set-roles")
def users_set_roles(
    user_id: int = typer.Argument(help="User ID."),
    role_id: list[int] = typer.Option(..., "--role-id", help="Role ID to assign. Repeat for multiple roles."),
):
    """Assign Privacy Profiles (roles) to a user. Replaces ALL existing roles."""
    client = get_client()
    try:
        current_roles = client.get(f"/api/User/{user_id}/Roles")
    except ApiError as e:
        handle_api_error(e)
        return
    new_ids = set(role_id)
    current_ids = {r["Id"] for r in current_roles} if isinstance(current_roles, list) else set()
    select_items = (
        [{"Id": rid, "Selected": True} for rid in new_ids]
        + [{"Id": rid, "Selected": False} for rid in current_ids - new_ids]
    )
    payload = {"RoleId": 0, "SelectItems": select_items, "ExcludeEtlConfigPacks": False}
    try:
        print_json(client.post(f"/api/User/{user_id}/Roles", json=payload))
    except ApiError as e:
        handle_api_error(e)


@app.command("sessions")
def users_sessions(
    raw: bool = typer.Option(False, "--raw", help="Output raw JSON."),
):
    """List active user sessions."""
    client = get_client()
    try:
        resp = client.get("/api/UserSession")
        data = resp.get("Data", resp) if isinstance(resp, dict) else resp
        if raw or not is_tty():
            print_json(data)
        else:
            print_table(data, SESSIONS_COLUMNS, label="sessions")
    except ApiError as e:
        handle_api_error(e)


@app.command("session-count")
def users_session_count():
    """Get the count of active sessions."""
    client = get_client()
    try:
        data = client.get("/api/UserSession/Count")
        print_json(data)
    except ApiError as e:
        handle_api_error(e)


@app.command("kill-session")
def users_kill_session(
    auth_token: str = typer.Argument(help="Auth token of the session to kill."),
    yes: bool = typer.Option(False, "--yes", "-y", help="Confirm without prompt."),
):
    """Kill (terminate) a user session by its auth token. Requires --yes to confirm."""
    if not yes:
        typer.echo("Error: killing a session requires --yes flag to confirm.", err=True)
        raise typer.Exit(1)
    client = get_client()
    try:
        client.delete(f"/api/UserSession/{auth_token}")
        print_json({"status": "killed", "authToken": auth_token})
    except ApiError as e:
        handle_api_error(e)
