<?php

declare(strict_types=1);

namespace ABS\Services;

use ABS\Core\Database;
use ABS\Core\Session;
use PDO;

final class AccessControlService
{
    /**
     * Fiecare element reprezintă o zonă configurabilă din aplicație.
     *
     * @return array<string,string>
     */
    public function modules(): array
    {
        return [
            'dashboard' => 'Dashboard',
            'modules' => 'Lista module',
            'agenda' => 'Agenda lunară',
            'users' => 'Utilizatori și permisiuni',
            'settings' => 'Setări',
            'parts-catalog' => 'Catalog și identificare piese',
            'parts-requests' => 'Cereri și ofertare piese',
            'opencart' => 'Integrare OpenCart',
            'gdpr' => 'GDPR Manager',
            'broker' => 'Broker și asigurări',
            'documents' => 'Management documente',
            'reports' => 'Rapoarte și statistici',
            'spv-invoices' => 'RO e-Factura / SPV',
            'notifications' => 'Notificări și e-mail',
            'api' => 'API aplicație mobilă',
            'audit' => 'Audit',
            'auto-acts' => 'Acte auto și contracte',
            'clients' => 'Clienți',
            'master-data' => 'Master Data',
            'offers' => 'Oferte',
            'orders' => 'Comenzi',
            'programari' => 'Programări',
            'saga' => 'Integrare SAGA',
            'service' => 'Service',
            'ssm-manager' => 'SSM Manager',
            'vehicles' => 'Vehicule',
            'warranty' => 'Garanții',
            'custom-modules' => 'Builder module personalizate',
        ];
    }

    public function user(): ?array
    {
        $user = Session::get('user');

        return is_array($user) ? $user : null;
    }

    public function isAuthenticated(): bool
    {
        return $this->user() !== null;
    }

    public function currentRole(): string
    {
        $user = $this->user();

        if ($user === null) {
            return '';
        }

        $role = trim((string) ($user['role'] ?? ''));

        /*
         * Compatibilitate pentru instalațiile existente înainte de Update 42:
         * primul cont creat rămâne SuperAdmin și nu poate fi blocat accidental.
         */
        if ($role === '' && (int) ($user['id'] ?? 0) === 1) {
            return 'SuperAdmin';
        }

        return $role !== '' ? $role : 'Angajat';
    }

    public function isSuperAdmin(): bool
    {
        return $this->currentRole() === 'SuperAdmin';
    }

    public function can(string $moduleKey): bool
    {
        if (!$this->isAuthenticated()) {
            return false;
        }

        if ($this->isSuperAdmin()) {
            return true;
        }

        $userId = (int) ($this->user()['id'] ?? 0);

        if ($userId <= 0) {
            return false;
        }

        try {
            $statement = Database::prepare(
                'SELECT can_access
                 FROM abs_user_module_permissions
                 WHERE user_id = :user_id
                   AND module_key = :module_key
                 LIMIT 1'
            );

            $statement->execute([
                ':user_id' => $userId,
                ':module_key' => $moduleKey,
            ]);

            return (int) $statement->fetchColumn() === 1;
        } catch (\Throwable) {
            /*
             * Înainte de importarea SQL-ului nu acordăm acces implicit.
             * Excepția este SuperAdmin, tratată mai sus.
             */
            return false;
        }
    }

    public function moduleForUri(string $uri): ?string
    {
        $path = parse_url($uri, PHP_URL_PATH) ?: '/';

        $rules = [
            '/dashboard' => 'dashboard',
            '/modules' => 'modules',
            '/agenda' => 'agenda',
            '/users' => 'users',
            '/settings' => 'settings',
            '/parts-catalog' => 'parts-catalog',
            '/parts-requests' => 'parts-requests',
            '/opencart' => 'opencart',
            '/gdpr' => 'gdpr',
            '/broker' => 'broker',
            '/documents' => 'documents',
            '/reports' => 'reports',
            '/spv-invoices' => 'spv-invoices',
            '/notifications' => 'notifications',
            '/api' => 'api',
            '/audit' => 'audit',
            '/acte-auto' => 'auto-acts',
            '/auto-acts' => 'auto-acts',
            '/clients' => 'clients',
            '/master-data' => 'master-data',
            '/offers' => 'offers',
            '/orders' => 'orders',
            '/programari' => 'programari',
            '/saga' => 'saga',
            '/service' => 'service',
            '/ssm' => 'ssm-manager',
            '/custom-modules/service' => 'service',
            '/vehicles' => 'vehicles',
            '/warranty' => 'warranty',
            '/custom-modules' => 'custom-modules',
        ];

        foreach ($rules as $prefix => $moduleKey) {
            if (
                $path === $prefix
                || str_starts_with($path, $prefix . '/')
            ) {
                return $moduleKey;
            }
        }

        return null;
    }

    public function canAccessUri(string $uri): bool
    {
        $moduleKey = $this->moduleForUri($uri);

        /*
         * Rutele autentificate care nu aparțin încă unui modul explicit
         * rămân accesibile. Orice modul nou trebuie adăugat în catalog.
         */
        return $moduleKey === null || $this->can($moduleKey);
    }

    public function permissionsForUser(int $userId): array
    {
        $result = array_fill_keys(
            array_keys($this->modules()),
            false
        );

        if ($userId <= 0) {
            return $result;
        }

        try {
            $statement = Database::prepare(
                'SELECT module_key, can_access
                 FROM abs_user_module_permissions
                 WHERE user_id = :user_id'
            );
            $statement->execute([':user_id' => $userId]);

            foreach (
                $statement->fetchAll(PDO::FETCH_ASSOC) ?: []
                as $row
            ) {
                $key = (string) ($row['module_key'] ?? '');

                if (array_key_exists($key, $result)) {
                    $result[$key] =
                        (int) ($row['can_access'] ?? 0) === 1;
                }
            }
        } catch (\Throwable) {
            return $result;
        }

        return $result;
    }

    public function savePermissions(
        int $userId,
        array $selectedModules
    ): void {
        $allowedKeys = array_keys($this->modules());
        $selected = array_fill_keys(
            array_values(array_intersect(
                $allowedKeys,
                array_map('strval', $selectedModules)
            )),
            true
        );

        Database::beginTransaction();

        try {
            $delete = Database::prepare(
                'DELETE FROM abs_user_module_permissions
                 WHERE user_id = :user_id'
            );
            $delete->execute([':user_id' => $userId]);

            $insert = Database::prepare(
                'INSERT INTO abs_user_module_permissions
                    (user_id, module_key, can_access)
                 VALUES
                    (:user_id, :module_key, :can_access)'
            );

            foreach ($allowedKeys as $moduleKey) {
                $insert->execute([
                    ':user_id' => $userId,
                    ':module_key' => $moduleKey,
                    ':can_access' =>
                        isset($selected[$moduleKey]) ? 1 : 0,
                ]);
            }

            Database::commit();
        } catch (\Throwable $exception) {
            Database::rollback();
            throw $exception;
        }
    }

    public function moduleKeyForCardSlug(string $slug): string
    {
        $aliases = [
            'gdpr-manager' => 'gdpr',
            'broker-insurance' => 'broker',
            'dashboard-management' => 'dashboard',
            'notifications-email' => 'notifications',
            'mobile-api' => 'api',
            'document-management' => 'documents',
            'reports-statistics' => 'reports',
            'spv-einvoices' => 'spv-invoices',
            'ssm-manager' => 'ssm-manager',
            'builder-custom-modules' => 'custom-modules',
        ];

        if (str_starts_with($slug, 'custom-')) {
            return 'custom-modules';
        }

        return $aliases[$slug] ?? $slug;
    }
}
