"""Dashboard API endpoints for Users management.

Exposes user CRUD, git sync, and default user assignment via REST.
"""

from __future__ import annotations

import time
from pathlib import Path
from typing import Any

import structlog
from fastapi import APIRouter, HTTPException
from pydantic import BaseModel, Field

from proxym.dashboard.users import User, UserManager

logger = structlog.get_logger()
router = APIRouter(prefix="/users", tags=["users"])


from proxym.dashboard.utils._emit_event import emit_event as _emit_event


# ── Request models ────────────────────────────────────────

class CreateUserRequest(BaseModel):
    name: str = Field(..., description="User display name")
    email: str = Field(..., description="User email address")
    username: str = Field("", description="Username/login")
    role: str = Field("developer", description="User role: admin, developer, viewer")
    is_default: bool = Field(False, description="Set as default/delegated user")


class UpdateUserRequest(BaseModel):
    name: str | None = Field(None, description="User display name")
    email: str | None = Field(None, description="User email address")
    username: str | None = Field(None, description="Username/login")
    role: str | None = Field(None, description="User role")
    is_default: bool | None = Field(None, description="Set as default user")
    is_active: bool | None = Field(None, description="Active status")


# ── Singleton helper ─────────────────────────────────────

def _users() -> UserManager:
    """Get the UserManager singleton with default persistence path."""
    from proxym.storage import DEFAULT_SQLITE_PATH
    return UserManager.get(DEFAULT_SQLITE_PATH)


# ── Endpoints ─────────────────────────────────────────────

@router.get("")
async def list_users(active_only: bool = False) -> dict[str, Any]:
    """List all users."""
    mgr = _users()
    users = mgr.list_users(active_only=active_only)
    return {
        "users": [u.summary() for u in users],
        "count": len(users),
        "default_user": mgr.get_default_user(),
        "git_sync": mgr.get_git_sync_metadata(),
    }


@router.post("")
async def create_user(req: CreateUserRequest) -> dict[str, Any]:
    """Create a new user."""
    mgr = _users()

    # Check for duplicate email
    if mgr.find_by_email(req.email):
        raise HTTPException(400, f"User with email '{req.email}' already exists")

    user = User(
        name=req.name,
        email=req.email,
        username=req.username or req.email.split("@")[0],
        role=req.role,
        is_default=req.is_default,
        git_configured=False,
    )
    created = mgr.create_user(user)
    logger.info("user_created", user_id=created.id, email=created.email)
    from proxym.domain.events import UserCreated
    _emit_event(UserCreated(
        aggregate_id="users",
        data={"user_id": created.id, "email": created.email, "name": created.name},
        actor="api",
    ))
    return created.summary()


@router.get("/sync-git")
async def sync_git_users(repo_path: str | None = None) -> dict[str, Any]:
    """Sync users from git commit history."""
    mgr = _users()
    path = Path(repo_path) if repo_path else None
    discovered = mgr.sync_from_git_log(path)
    mgr.set_git_sync_metadata(time.time(), len(discovered))
    from proxym.domain.events import UsersSyncedFromGit
    _emit_event(UsersSyncedFromGit(
        aggregate_id="users",
        data={
            "discovered_count": len(discovered),
            "discovered_emails": [u.email for u in discovered],
            "total_users": len(mgr.list_users()),
        },
        actor="api",
    ))
    return {
        "discovered": len(discovered),
        "users": [u.summary() for u in discovered],
        "total_users": len(mgr.list_users()),
        "git_sync": mgr.get_git_sync_metadata(),
    }


@router.get("/default")
async def get_default_user() -> dict[str, Any]:
    """Get the default/delegated user."""
    mgr = _users()
    default = mgr.get_default_user()
    if not default:
        raise HTTPException(404, "No default user configured")
    return default


@router.post("/{user_id}/set-default")
async def set_default_user(user_id: str) -> dict[str, Any]:
    """Set a user as the default/delegated user."""
    mgr = _users()
    user = mgr.get_user(user_id)
    if not user:
        raise HTTPException(404, f"User '{user_id}' not found")

    updated = mgr.update_user(user_id, {"is_default": True})
    logger.info("default_user_set", user_id=user_id)
    from proxym.domain.events import UserUpdated
    _emit_event(UserUpdated(
        aggregate_id="users",
        data={"user_id": user_id, "updates": ["is_default"]},
        actor="api",
    ))
    return updated.summary()


@router.get("/{user_id}")
async def get_user(user_id: str) -> dict[str, Any]:
    """Get a specific user."""
    mgr = _users()
    user = mgr.get_user(user_id)
    if not user:
        raise HTTPException(404, f"User '{user_id}' not found")
    return user.summary()


@router.put("/{user_id}")
async def update_user(user_id: str, req: UpdateUserRequest) -> dict[str, Any]:
    """Update a user."""
    mgr = _users()
    user = mgr.get_user(user_id)
    if not user:
        raise HTTPException(404, f"User '{user_id}' not found")

    updates = req.model_dump(exclude_unset=True)
    if not updates:
        return user.summary()

    updated = mgr.update_user(user_id, updates)
    logger.info("user_updated", user_id=user_id, updates=list(updates.keys()))
    from proxym.domain.events import UserUpdated
    _emit_event(UserUpdated(
        aggregate_id="users",
        data={"user_id": user_id, "updates": list(updates.keys())},
        actor="api",
    ))
    return updated.summary()


@router.delete("/{user_id}")
async def delete_user(user_id: str) -> dict[str, Any]:
    """Delete a user."""
    mgr = _users()
    user = mgr.get_user(user_id)
    if not user:
        raise HTTPException(404, f"User '{user_id}' not found")

    # Don't delete the last default user without setting a new one
    if user.is_default:
        other_default_candidates = [
            u for u in mgr.list_users() if u.id != user_id and u.is_active
        ]
        if other_default_candidates:
            # Set first other user as default
            mgr.update_user(other_default_candidates[0].id, {"is_default": True})

    if mgr.delete_user(user_id):
        logger.info("user_deleted", user_id=user_id)
        from proxym.domain.events import UserDeleted
        _emit_event(UserDeleted(
            aggregate_id="users",
            data={"user_id": user_id, "email": user.email},
            actor="api",
        ))
        return {"ok": True, "deleted": user_id}

    raise HTTPException(500, "Failed to delete user")
