<?php

namespace MintyPHP\Service\Access;

use MintyPHP\Repository\Access\RoleRepositoryInterface;
use MintyPHP\Service\Audit\SystemAuditService;
use MintyPHP\Service\Directory\DirectorySettingsGateway;

class RoleService
{
    public function __construct(
        private readonly RoleRepositoryInterface $roleRepository,
        private readonly DirectorySettingsGateway $settingsGateway,
        private readonly SystemAuditService $systemAuditService
    ) {
    }

    public function list(): array
    {
        return $this->roleRepository->list();
    }

    public function listActive(): array
    {
        return $this->roleRepository->listActive();
    }

    public function listPaged(array $options): array
    {
        return $this->roleRepository->listPaged($options);
    }

    public function findByUuid(string $uuid): ?array
    {
        return $this->roleRepository->findByUuid($uuid);
    }

    public function findById(int $id): ?array
    {
        return $this->roleRepository->find($id);
    }

    public function createFromAdmin(array $input, int $currentUserId = 0): array
    {
        $form = $this->sanitizeBase($input);
        $errors = $this->validateBase($form, 0);

        if ($errors) {
            return ['ok' => false, 'errors' => $errors, 'form' => $form];
        }

        $createdId = $this->roleRepository->create([
            'description' => $form['description'],
            'code' => $form['code'] ?: null,
            'active' => $form['active'],
            'created_by' => $currentUserId > 0 ? $currentUserId : null,
        ]);

        if (!$createdId) {
            return ['ok' => false, 'errors' => [t('Role can not be created')], 'form' => $form];
        }

        $createdRole = $this->roleRepository->find((int) $createdId);
        $uuid = $createdRole['uuid'] ?? null;
        if (!empty($input['is_default'])) {
            $this->settingsGateway->setDefaultRoleId((int) $createdId);
        }

        $this->systemAuditService->record('admin.roles.create', 'success', [
            'actor_user_id' => $currentUserId > 0 ? $currentUserId : null,
            'target_type' => 'role',
            'target_id' => (int) $createdId,
            'target_uuid' => is_string($uuid) ? $uuid : '',
            'metadata' => ['active' => $form['active']],
        ]);

        return ['ok' => true, 'form' => $form, 'uuid' => $uuid, 'id' => (int) $createdId];
    }

    public function updateFromAdmin(int $roleId, array $input, int $currentUserId = 0): array
    {
        $form = $this->sanitizeBase($input);
        $errors = $this->validateBase($form, $roleId);

        if ($errors) {
            return ['ok' => false, 'errors' => $errors, 'form' => $form];
        }

        $existingBefore = $this->roleRepository->find($roleId) ?? [];

        $updated = $this->roleRepository->update($roleId, [
            'description' => $form['description'],
            'code' => $form['code'] ?: null,
            'active' => $form['active'],
            'modified_by' => $currentUserId > 0 ? $currentUserId : null,
        ]);

        if (!$updated) {
            return ['ok' => false, 'errors' => [t('Role can not be updated')], 'form' => $form];
        }

        $this->systemAuditService->record('admin.roles.update', 'success', [
            'actor_user_id' => $currentUserId > 0 ? $currentUserId : null,
            'target_type' => 'role',
            'target_id' => $roleId,
            'target_uuid' => (string) ($existingBefore['uuid'] ?? ''),
            'before' => ['active' => $existingBefore['active'] ?? null],
            'after' => ['active' => $form['active']],
        ]);

        return ['ok' => true, 'form' => $form];
    }

    public function deleteByUuid(string $uuid): array
    {
        $uuid = trim($uuid);
        if ($uuid === '') {
            return ['ok' => false, 'status' => 404, 'error' => 'not_found'];
        }

        $role = $this->roleRepository->findByUuid($uuid);
        if (!$role || !isset($role['id'])) {
            return ['ok' => false, 'status' => 404, 'error' => 'not_found'];
        }

        if (($role['description'] ?? '') === 'Admin') {
            return ['ok' => false, 'status' => 403, 'error' => 'admin_role_protected'];
        }

        $deleted = $this->roleRepository->delete((int) $role['id']);
        if (!$deleted) {
            return ['ok' => false, 'status' => 500, 'error' => 'delete_failed'];
        }

        $this->systemAuditService->record('admin.roles.delete', 'success', [
            'target_type' => 'role',
            'target_id' => (int) $role['id'],
            'target_uuid' => (string) ($role['uuid'] ?? ''),
        ]);

        return ['ok' => true, 'role' => $role];
    }

    private function sanitizeBase(array $input): array
    {
        return [
            'description' => trim((string) ($input['description'] ?? '')),
            'code' => trim((string) ($input['code'] ?? '')),
            'active' => $this->normalizeActive($input['active'] ?? 1),
        ];
    }

    private function validateBase(array $form, int $excludeId): array
    {
        $errors = [];
        if ($form['description'] === '') {
            $errors[] = t('Description cannot be empty');
        }
        $code = $form['code'] ?? '';
        if ($code !== '' && $this->roleRepository->existsByCode($code, $excludeId)) {
            $errors[] = t('Role code already exists');
        }
        return $errors;
    }

    private function normalizeActive($value): int
    {
        $value = strtolower(trim((string) $value));
        if (in_array($value, ['0', 'false', 'inactive'], true)) {
            return 0;
        }
        return 1;
    }

}
