<?php

declare(strict_types=1);

namespace App\Controllers;

use App\ApiClient\AdminClient;
use App\ApiClient\ApiException;
use App\Auth\SessionManager;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Slim\Views\Twig;

/**
 * `/app/users` — admin-only roster + disable/enable toggle.
 *
 * SEC_REVIEW F11. The page is a defensive minimum: list every user the
 * api knows about, and provide one POST per row to flip `disabled`.
 * Heavier user-management features (delete, role override) are not
 * exposed yet; OIDC role still flows from `oidc_role_mappings`.
 */
final class UsersController
{
    use CrudControllerSupport;

    public function __construct(
        private readonly Twig $twigEngine,
        private readonly SessionManager $sessionManager,
        private readonly AdminClient $admin,
    ) {
    }

    protected function twig(): Twig
    {
        return $this->twigEngine;
    }

    protected function sessions(): SessionManager
    {
        return $this->sessionManager;
    }

    public function index(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
    {
        $redirect = $this->requireUser($request, $response);
        if ($redirect !== null) {
            return $redirect;
        }
        $user = $this->sessionManager->getUser();
        \assert($user !== null);

        if (!$this->userIs($user, 'admin')) {
            return $this->twigEngine->render($response->withStatus(403), 'pages/error.twig', [
                'status' => 403,
                'is_client_error' => true,
                'message' => 'Admin role required.',
            ]);
        }

        try {
            $list = $this->admin->listUsers($user->userId);
        } catch (ApiException $e) {
            $list = ['items' => [], 'total' => 0];
            $this->flashFromException($e);
        }

        return $this->twigEngine->render($response, 'pages/users/index.twig', [
            'active_section' => 'users',
            'list' => $list,
            'acting_user_id' => $user->userId,
        ]);
    }

    /**
     * @param array{id: string} $args
     */
    public function disable(ServerRequestInterface $request, ResponseInterface $response, array $args): ResponseInterface
    {
        return $this->setDisabled($request, $response, $args, true);
    }

    /**
     * @param array{id: string} $args
     */
    public function enable(ServerRequestInterface $request, ResponseInterface $response, array $args): ResponseInterface
    {
        return $this->setDisabled($request, $response, $args, false);
    }

    /**
     * @param array{id: string} $args
     */
    private function setDisabled(
        ServerRequestInterface $request,
        ResponseInterface $response,
        array $args,
        bool $disabled,
    ): ResponseInterface {
        $redirect = $this->requireUser($request, $response);
        if ($redirect !== null) {
            return $redirect;
        }
        $user = $this->sessionManager->getUser();
        \assert($user !== null);

        if (!$this->userIs($user, 'admin')) {
            return $response->withStatus(303)->withHeader('Location', '/app/users');
        }

        $id = $this->parseId($args['id']);
        if ($id === null) {
            return $response->withStatus(303)->withHeader('Location', '/app/users');
        }

        try {
            $this->admin->setUserDisabled($user->userId, $id, $disabled);
            $this->sessionManager->flash('success', $disabled ? 'User disabled.' : 'User enabled.');
        } catch (ApiException $e) {
            // Map api 409s ("cannot_disable_self", "cannot_disable_local_admin")
            // to a friendly flash; everything else flows through the standard
            // exception → flash mapper.
            if ($e->statusCode === 409 && $e->apiError !== null) {
                $this->sessionManager->flash('error', match ($e->apiError) {
                    'cannot_disable_self' => 'You cannot disable your own account.',
                    'cannot_disable_local_admin' => 'The local admin cannot be disabled here. Unset LOCAL_ADMIN_PASSWORD_HASH instead.',
                    default => $e->apiError,
                });
            } else {
                $this->flashFromException($e);
            }
        }

        return $response->withStatus(303)->withHeader('Location', '/app/users');
    }
}
