from pathlib import Path

from app.core.app_settings import apply_settings_to_app, get_settings_payload, write_settings
from app.core.audit_log import read_audit_events, write_audit_event
from app.core.config import settings
from app.core.install_secrets import install_secrets_payload, reveal_install_secret
from app.core.jwt_denylist import bump_auth_epoch
from app.core.security import hash_password
from app.modules.admin.security_diagnostics import build_security_diagnostics_report
from app.modules.auth.service import revoke_user_refresh_family
from app.modules.users import repository


def list_admin_users(page: int, limit: int) -> dict:
    users, total = repository.list_users(page, limit)
    return {
        "data": [
            {
                "id": user.id,
                "email": user.email,
                "role": user.role,
                "is_superuser": user.is_superuser,
                "status": user.status,
            }
            for user in users
        ],
        "meta": {"total": total, "page": page, "limit": limit},
    }


def _ensure_last_superuser_protection(target, role: str | None, is_superuser: bool | None) -> None:
    super_count = repository.count_superusers()
    role_becomes_admin = target.role if role is None else role
    super_becomes_true = target.is_superuser if is_superuser is None else is_superuser
    is_losing_super = target.role == "admin" and target.is_superuser and (
        role_becomes_admin != "admin" or not super_becomes_true
    )
    if is_losing_super and super_count <= 1:
        raise ValueError("LAST_SUPERUSER_PROTECTED")


def patch_user(
    admin_user, target_user_id: str, role: str | None, status: str | None, is_superuser: bool | None = None
) -> dict:
    target = repository.get_user_by_id(target_user_id)
    if not target:
        raise ValueError("USER_NOT_FOUND")
    if admin_user.id == target_user_id and role and role != "admin":
        raise ValueError("SELF_DEMOTION_FORBIDDEN")
    if admin_user.id == target_user_id and is_superuser is False:
        raise ValueError("SELF_DEMOTION_FORBIDDEN")
    if admin_user.id == target_user_id and status == "blocked":
        raise ValueError("SELF_BLOCK_FORBIDDEN")

    admin_count = repository.count_admins()
    if target.role == "admin" and role and role != "admin" and admin_count <= 1:
        raise ValueError("LAST_ADMIN_PROTECTED")
    _ensure_last_superuser_protection(target, role, is_superuser)

    if role:
        target.role = role
    if is_superuser is not None:
        target.is_superuser = bool(is_superuser)
    if status:
        target.status = status
        if status == "blocked":
            bump_auth_epoch(target.id)
            revoke_user_refresh_family(target.id)
    repository.update_user(target)
    write_audit_event(
        action="admin.user.patch",
        actor_user_id=admin_user.id,
        actor_email=admin_user.email,
        details={"target_user_id": target.id},
    )
    return {
        "id": target.id,
        "email": target.email,
        "role": target.role,
        "is_superuser": target.is_superuser,
        "status": target.status,
    }


def create_admin_user(admin_user, email: str, password: str, role: str, is_superuser: bool, status: str) -> dict:
    if repository.get_user_by_email(email):
        raise ValueError("USER_EXISTS")
    user = repository.create_user(
        email=email,
        password_hash=hash_password(password),
        role=role,
        is_superuser=is_superuser,
        status=status,
    )
    write_audit_event(
        action="admin.user.create",
        actor_user_id=admin_user.id,
        actor_email=admin_user.email,
        details={"target_user_id": user.id},
    )
    return {
        "id": user.id,
        "email": user.email,
        "role": user.role,
        "is_superuser": user.is_superuser,
        "status": user.status,
    }


def reset_user_password(admin_user, target_user_id: str, password: str) -> dict:
    target = repository.get_user_by_id(target_user_id)
    if not target:
        raise ValueError("USER_NOT_FOUND")
    target.password_hash = hash_password(password)
    repository.update_user(target)
    bump_auth_epoch(target.id)
    revoke_user_refresh_family(target.id)
    write_audit_event(
        action="admin.user.reset_password",
        actor_user_id=admin_user.id,
        actor_email=admin_user.email,
        details={"target_user_id": target.id},
    )
    return {"status": "ok"}


def delete_admin_user(admin_user, target_user_id: str) -> dict:
    target = repository.get_user_by_id(target_user_id)
    if not target:
        raise ValueError("USER_NOT_FOUND")
    if admin_user.id == target.id:
        raise ValueError("SELF_DELETE_FORBIDDEN")
    _ensure_last_superuser_protection(target, "user", False)
    if target.role == "admin" and repository.count_admins() <= 1:
        raise ValueError("LAST_ADMIN_PROTECTED")
    repository.delete_user(target.id)
    revoke_user_refresh_family(target.id)
    write_audit_event(
        action="admin.user.delete",
        actor_user_id=admin_user.id,
        actor_email=admin_user.email,
        details={"target_user_id": target.id},
    )
    return {"status": "deleted"}


def get_admin_summary() -> dict:
    return {
        "users_count": repository.count_users(),
        "registrations_day": repository.count_users_registered_today(),
        "admins_count": repository.count_admins(),
        "superusers_count": repository.count_superusers(),
    }


def get_admin_settings() -> dict:
    return get_settings_payload()


def patch_admin_settings(admin_user, values: dict) -> dict:
    merged = write_settings(values)
    apply_settings_to_app(merged)
    write_audit_event(
        action="admin.settings.patch",
        actor_user_id=admin_user.id,
        actor_email=admin_user.email,
        details={"updated_keys": sorted(values.keys())},
    )
    return get_settings_payload()


def get_diagnostics_report() -> dict:
    return build_security_diagnostics_report()


def list_activity_feed(limit: int = 200) -> dict:
    return {"events": read_audit_events(limit=limit)}


def record_ui_activity(admin_user, event: str, meta: dict | None) -> dict:
    write_audit_event(
        action=f"ui.{event}",
        actor_user_id=admin_user.id,
        actor_email=admin_user.email,
        details=meta or {},
    )
    return {"status": "ok"}


def get_server_log_tail(lines: int = 200) -> dict:
    path = Path(settings.server_log_path)
    if not path.exists():
        return {"lines": []}
    return {"lines": path.read_text(encoding="utf-8", errors="ignore").splitlines()[-lines:]}


def get_install_secrets() -> dict:
    return install_secrets_payload()


def reveal_secret(admin_user, key: str) -> dict:
    value = reveal_install_secret(key)
    write_audit_event(
        action="admin.secrets.reveal",
        actor_user_id=admin_user.id,
        actor_email=admin_user.email,
        details={"key": key},
    )
    return {"key": key, "value": value}
