"""CQRS handlers for user management.

Wraps UserManager operations, emits domain events, and tracks
git sync metadata so the system knows when it last synced.
"""

from __future__ import annotations

from pathlib import Path
from typing import Any

import structlog

from proxym.domain.commands.user_commands import (
    CreateUserCommand,
    DeleteUserCommand,
    SyncGitUsersCommand,
    UpdateUserCommand,
)
from proxym.domain.events import (
    EventStore,
    UserCreated,
    UserDeleted,
    UsersSyncedFromGit,
    UserUpdated,
)
from proxym.domain.queries.user_queries import (
    GetDefaultUserQuery,
    GetGitSyncStatusQuery,
    GetUserQuery,
    ListUsersQuery,
)

logger = structlog.get_logger()

USERS_AGGREGATE_ID = "users"


class UserCommandHandler:
    """Handle user commands, delegate to UserManager, emit events."""

    def __init__(self, user_manager, event_store: EventStore) -> None:
        self._mgr = user_manager
        self._store = event_store

    def handle(self, command: Any) -> dict[str, Any]:
        if isinstance(command, CreateUserCommand):
            return self._handle_create(command)
        if isinstance(command, UpdateUserCommand):
            return self._handle_update(command)
        if isinstance(command, DeleteUserCommand):
            return self._handle_delete(command)
        if isinstance(command, SyncGitUsersCommand):
            return self._handle_sync_git(command)
        raise ValueError(f"Unknown command: {type(command).__name__}")

    def _handle_create(self, cmd: CreateUserCommand) -> dict[str, Any]:
        from proxym.dashboard.users import User

        existing = self._mgr.find_by_email(cmd.email)
        if existing:
            raise ValueError(f"User with email '{cmd.email}' already exists")

        user = User(
            name=cmd.name,
            email=cmd.email,
            username=cmd.username or cmd.email.split("@")[0],
            role=cmd.role,
            is_default=cmd.is_default,
            git_configured=cmd.git_configured,
        )
        created = self._mgr.create_user(user)

        self._store.append(
            UserCreated(
                aggregate_id=USERS_AGGREGATE_ID,
                data={"user_id": created.id, "email": created.email, "name": created.name},
                actor=cmd.actor,
            )
        )
        return created.summary()

    def _handle_update(self, cmd: UpdateUserCommand) -> dict[str, Any]:
        user = self._mgr.get_user(cmd.user_id)
        if not user:
            raise ValueError(f"User '{cmd.user_id}' not found")

        updated = self._mgr.update_user(cmd.user_id, cmd.updates)

        self._store.append(
            UserUpdated(
                aggregate_id=USERS_AGGREGATE_ID,
                data={"user_id": cmd.user_id, "updates": list(cmd.updates.keys())},
                actor=cmd.actor,
            )
        )
        return updated.summary()

    def _handle_delete(self, cmd: DeleteUserCommand) -> dict[str, Any]:
        user = self._mgr.get_user(cmd.user_id)
        if not user:
            raise ValueError(f"User '{cmd.user_id}' not found")

        email = user.email
        self._mgr.delete_user(cmd.user_id)

        self._store.append(
            UserDeleted(
                aggregate_id=USERS_AGGREGATE_ID,
                data={"user_id": cmd.user_id, "email": email},
                actor=cmd.actor,
            )
        )
        return {"ok": True, "deleted": cmd.user_id}

    def _handle_sync_git(self, cmd: SyncGitUsersCommand) -> dict[str, Any]:
        path = Path(cmd.repo_path) if cmd.repo_path else None
        discovered = self._mgr.sync_from_git_log(path)

        import time
        self._mgr.set_git_sync_metadata(time.time(), len(discovered))

        self._store.append(
            UsersSyncedFromGit(
                aggregate_id=USERS_AGGREGATE_ID,
                data={
                    "discovered_count": len(discovered),
                    "discovered_emails": [u.email for u in discovered],
                    "total_users": len(self._mgr.list_users()),
                },
                actor=cmd.actor,
            )
        )
        return {
            "discovered": len(discovered),
            "users": [u.summary() for u in discovered],
            "total_users": len(self._mgr.list_users()),
        }


class UserQueryHandler:
    """Handle user read queries."""

    def __init__(self, user_manager) -> None:
        self._mgr = user_manager

    def handle(self, query: Any) -> Any:
        if isinstance(query, ListUsersQuery):
            return self._handle_list(query)
        if isinstance(query, GetUserQuery):
            return self._handle_get(query)
        if isinstance(query, GetDefaultUserQuery):
            return self._handle_default(query)
        if isinstance(query, GetGitSyncStatusQuery):
            return self._handle_sync_status(query)
        raise ValueError(f"Unknown query: {type(query).__name__}")

    def _handle_list(self, query: ListUsersQuery) -> dict[str, Any]:
        users = self._mgr.list_users(active_only=query.active_only)
        return {
            "users": [u.summary() for u in users],
            "count": len(users),
            "default_user": self._mgr.get_default_user(),
            "git_sync": self._mgr.get_git_sync_metadata(),
        }

    def _handle_get(self, query: GetUserQuery) -> dict[str, Any] | None:
        user = self._mgr.get_user(query.user_id)
        return user.summary() if user else None

    def _handle_default(self, query: GetDefaultUserQuery) -> dict[str, Any] | None:
        return self._mgr.get_default_user()

    def _handle_sync_status(self, query: GetGitSyncStatusQuery) -> dict[str, Any]:
        return self._mgr.get_git_sync_metadata()
