<?php

declare(strict_types=1);

namespace App\Controllers;

use App\Core\BaseController;
use App\Core\Database;
use App\Core\Request;
use App\Core\Response;
use App\Helpers\AjaxResponse;
use App\Helpers\Paginator;
use App\Models\UserModel;
use App\Services\UserService;

final class UserController extends BaseController
{
    public function index(Request $request): Response
    {
        $model = new UserModel();
        $paginator = Paginator::fromRequest($request, defaultPerPage: 20);

        $filters = [
            'search' => $request->query('search'),
            'status' => $request->query('status'),
            'role_id' => $request->query('role_id'),
            'department_id' => $request->query('department_id'),
        ];

        $rows = $model->paginatedList($filters, $paginator);

        if ($request->isAjax() || $request->isJson()) {
            return AjaxResponse::success(['rows' => $rows, 'meta' => $paginator->meta()]);
        }

        return $this->view('users/index', [
            'title' => 'User Management',
            'activeNav' => 'users',
            'breadcrumbs' => [['Home', 'dashboard'], ['Administration', 'users'], ['Users', 'users']],
            'rows' => $rows,
            'meta' => $paginator->meta(),
            'roles' => $this->rolesForSelect(),
            'departments' => $this->departmentsForSelect(),
            'businessLines' => $this->businessLinesForSelect(),
        ]);
    }

    public function show(Request $request, array $params): Response
    {
        $user = (new UserModel())->findWithRelations((int) $params['id']);

        if ($user === null) {
            return AjaxResponse::notFound('User not found.');
        }

        $businessLineIds = Database::connection()
            ->prepare('SELECT business_line_id FROM user_business_lines WHERE user_id = :id');
        $businessLineIds->execute(['id' => $params['id']]);

        $user['business_line_ids'] = $businessLineIds->fetchAll(\PDO::FETCH_COLUMN);

        return AjaxResponse::success($user);
    }

    public function store(Request $request): Response
    {
        $data = $this->validateOrFail($request, [
            'first_name' => 'required|string|max:100',
            'last_name' => 'nullable|string|max:100',
            'email' => 'required|email|max:191|unique:users,email',
            'phone' => 'nullable|string|max:30',
            'job_title' => 'nullable|string|max:120',
            'role_id' => 'required|integer|exists:roles,id',
            'department_id' => 'nullable|integer|exists:departments,id',
        ]);

        $data['business_line_ids'] = array_map('intval', (array) $request->input('business_line_ids', []));

        $userId = (new UserService())->invite($data, $this->currentUserId());

        return AjaxResponse::created(['id' => $userId], 'Invitation sent.');
    }

    public function update(Request $request, array $params): Response
    {
        $userId = (int) $params['id'];

        $data = $this->validateOrFail($request, [
            'first_name' => 'required|string|max:100',
            'last_name' => 'nullable|string|max:100',
            'phone' => 'nullable|string|max:30',
            'job_title' => 'nullable|string|max:120',
            'role_id' => 'required|integer|exists:roles,id',
            'department_id' => 'nullable|integer|exists:departments,id',
        ]);

        $data['business_line_ids'] = array_map('intval', (array) $request->input('business_line_ids', []));

        (new UserService())->update($userId, $data, $this->currentUserId());

        return AjaxResponse::success((new UserModel())->findWithRelations($userId), 'User updated.');
    }

    public function deactivate(Request $request, array $params): Response
    {
        $userId = (int) $params['id'];

        if ($userId === $this->currentUserId()) {
            return AjaxResponse::error('You cannot deactivate your own account.', 422);
        }

        (new UserService())->deactivate($userId, $this->currentUserId());

        return AjaxResponse::success(null, 'User deactivated.');
    }

    public function reactivate(Request $request, array $params): Response
    {
        (new UserService())->reactivate((int) $params['id'], $this->currentUserId());

        return AjaxResponse::success(null, 'User reactivated.');
    }

    public function resetPassword(Request $request, array $params): Response
    {
        (new UserService())->adminResetPassword((int) $params['id'], $this->currentUserId());

        return AjaxResponse::success(null, 'A password reset link has been sent to the user.');
    }

    public function destroy(Request $request, array $params): Response
    {
        $userId = (int) $params['id'];

        if ($userId === $this->currentUserId()) {
            return AjaxResponse::error('You cannot delete your own account.', 422);
        }

        (new UserModel())->delete($userId, $this->currentUserId());
        \App\Services\ActivityLogger::record('user', $userId, 'user_deleted', 'User account deleted', category: 'admin');

        return AjaxResponse::success(null, 'User deleted.');
    }

    private function rolesForSelect(): array
    {
        return Database::connection()->query('SELECT id, name FROM roles ORDER BY name')->fetchAll();
    }

    private function departmentsForSelect(): array
    {
        return Database::connection()->query('SELECT id, name FROM departments WHERE deleted_at IS NULL ORDER BY name')->fetchAll();
    }

    private function businessLinesForSelect(): array
    {
        return Database::connection()->query('SELECT id, name FROM business_lines ORDER BY name')->fetchAll();
    }
}
