<?php
namespace App\Core;

use App\Models\User;

final class Permission {
    private const FAMILY_PORTAL_ROLES = ['famille', 'habitant_portail'];
    private const PLATFORM_ADMIN_ROLES = ['super_admin', 'superadmin'];
    private const ADHERENT_DATA_PREFIXES = [
        'clients.',
        'familles.',
        'family.',
        'membres.',
        'inscriptions.',
        'demandes_inscription.',
        'documents.family.',
        'consentements.',
    ];
    private const SPACE_PERMISSION_PREFIXES = [
        'famille' => [
            'clients.', 'familles.', 'family.', 'membres.', 'inscriptions.',
            'demandes_inscription.', 'documents.family.', 'consentements.',
            'factures.portal.', 'paiements.portal.',
        ],
        'professeur' => [
            'professeur.portal.', 'planning.', 'presences.', 'agenda.',
            'demandes_inscription.waiting.',
        ],
        'direction' => [
            'clients.', 'familles.', 'membres.', 'inscriptions.',
            'demandes_inscription.', 'professeurs.', 'ateliers.', 'planning.',
            'presences.', 'communications.', 'tarifs.', 'direction.',
            'consentements.', 'documents.family.',
        ],
        'facturation' => [
            'facturation.', 'paiements.', 'comptabilite.', 'tresorerie.',
            'caisses.', 'remises.', 'factures.', 'avoirs.',
        ],
        'axiom' => [
            'utilisateurs.', 'administration.', 'axiom.', 'updates.',
            'backups.', 'parametres.', 'roles.', 'permissions.', 'audit.',
            'foundation.', 'modules.', 'system.',
        ],
    ];

    public static function activeSpace(): string {
        $space = (string)($_SESSION['axiom_space'] ?? '');
        return in_array($space, ['famille','professeur','direction','facturation','axiom'], true)
            ? $space
            : '';
    }

    public static function allowsPathInActiveSpace(string $path): bool {
        return true;
    }

    public static function requireActiveSpacePath(string $path): void {
        // Compatibilité : l’espace organise l’interface, jamais l’autorisation.
    }

    public static function roleCodes(): array {
        $id = Auth::id();
        if (!$id) return [];
        $stmt = Database::connection()->prepare(
            "SELECT DISTINCT r.code
             FROM utilisateur_roles ur
             INNER JOIN roles r ON r.id=ur.role_id
             WHERE ur.utilisateur_id=?
               AND r.actif=1
               AND r.deleted_at IS NULL"
        );
        $stmt->execute([$id]);
        return array_values(array_filter(array_map('strval', $stmt->fetchAll(\PDO::FETCH_COLUMN))));
    }

    public static function isProfessorOnly(): bool {
        $roles = self::roleCodes();
        return in_array('professeur_animateur', $roles, true)
            && count(array_diff($roles, ['professeur_animateur'])) === 0;
    }

    /**
     * A portal identity is a security property of the account, not of the
     * currently selected visual space. A family-linked account therefore
     * remains scoped even if an overly broad permission is granted by mistake.
     */
    public static function isFamilyPortalIdentity(): bool {
        $id = Auth::id();
        if (!$id) {
            return false;
        }

        // Tout compte qui ouvre l’espace Famille adopte strictement la portée
        // portail. Sans rattachement, aucune fiche personnelle n’est exposée.
        if (self::activeSpace() === 'famille') {
            return true;
        }

        if (count(array_intersect(self::roleCodes(), self::FAMILY_PORTAL_ROLES)) > 0) {
            return true;
        }

        $stmt = Database::connection()->prepare(
            'SELECT 1 FROM cda_family_accounts WHERE utilisateur_id = :user_id LIMIT 1'
        );
        $stmt->execute(['user_id' => $id]);
        return (bool)$stmt->fetchColumn();
    }

    public static function familyPortalClientId(): ?int {
        $id = Auth::id();
        if (!$id || !self::isFamilyPortalIdentity()) {
            return null;
        }

        if (self::activeSpace() === 'famille' && self::isSuperAdmin()) {
            return PortalSimulation::clientId();
        }

        $stmt = Database::connection()->prepare(
            'SELECT client_id
             FROM cda_family_accounts
             WHERE utilisateur_id = :user_id
             LIMIT 1'
        );
        $stmt->execute(['user_id' => $id]);
        $clientId = (int)$stmt->fetchColumn();
        return $clientId > 0 ? $clientId : null;
    }

    public static function canAccessClient(int $clientId): bool {
        if ($clientId <= 0) {
            return false;
        }
        if (!self::isFamilyPortalIdentity()) {
            return self::canAny('clients.view', 'clients.edit', 'clients.create');
        }
        return self::familyPortalClientId() === $clientId;
    }

    public static function canViewFullProfessorRh(): bool {
        if (self::activeSpace() === 'professeur') {
            return false;
        }
        return count(array_intersect(
            self::roleCodes(),
            ['super_admin', 'direction', 'rh']
        )) > 0;
    }

    public static function canValidateAssignments(): bool {
        $id = Auth::id();
        if (!$id) return false;
        if (self::activeSpace() !== 'direction') return false;
        return self::can('demandes_inscription.validate')
            || User::hasAnyRole($id, 'super_admin', 'superadmin', 'direction');
    }

    public static function isAdmin(): bool {
        return self::activeSpace() === 'axiom'
            && count(array_intersect(self::roleCodes(), ['super_admin','superadmin','administration','admin']))>0;
    }

    public static function isSuperAdmin(): bool {
        return count(array_intersect(self::roleCodes(), ['super_admin','superadmin']))>0;
    }

    public static function can(string $code): bool {
        $id = Auth::id();
        if (!$id) {
            return false;
        }

        // Le Super-admin authentifié conserve toujours ses droits réels.
        // L'espace sélectionné et l'identité simulée ne servent qu'à adapter
        // l'interface et la portée des données affichées.
        if (self::isSuperAdmin()) {
            return true;
        }

        if (!self::isAllowedInActiveSpace($code)) {
            return false;
        }

        // Le portail Famille est strictement en lecture et demandes pour les
        // comptes portail réels. Une simulation Super-admin est déjà traitée
        // ci-dessus et ne réduit jamais ses privilèges authentifiés.
        // lorsqu'il est simulé par un compte interne ou Super-admin.
        if (self::activeSpace() === 'famille') {
            $allowed = [
                'clients.view',
                'family.profile.view',
                'membres.view',
                'family.messages.view',
                'family.messages.create',
                'factures.portal.view',
                'paiements.portal.view',
            ];
            if (!in_array($code, $allowed, true)) {
                return false;
            }
        }

        return User::hasPermission($id, $code);
    }

    public static function isAllowedInActiveSpace(string $code): bool {
        $space = self::activeSpace();
        if ($space === '') {
            return true;
        }

        if ($space === 'axiom' && self::isSuperAdmin()) {
            return true;
        }

        if ($space === 'famille') {
            return in_array($code, [
                'clients.view',
                'family.profile.view',
                'membres.view',
                'family.messages.view',
                'family.messages.create',
                'factures.portal.view',
                'paiements.portal.view',
            ], true);
        }

        if ($code === 'recherche.globale.use') {
            return in_array($space, ['direction', 'facturation'], true);
        }

        foreach (self::SPACE_PERMISSION_PREFIXES[$space] ?? [] as $prefix) {
            if (str_starts_with($code, $prefix)) {
                return true;
            }
        }
        return false;
    }

    public static function isPlatformAdminOnly(): bool {
        $roles = self::roleCodes();
        if (count(array_intersect($roles, self::PLATFORM_ADMIN_ROLES)) === 0) {
            return false;
        }
        return count(array_diff($roles, self::PLATFORM_ADMIN_ROLES)) === 0;
    }

    private static function isAdherentDataPermission(string $code): bool {
        foreach (self::ADHERENT_DATA_PREFIXES as $prefix) {
            if (str_starts_with($code, $prefix)) {
                return true;
            }
        }
        return false;
    }

    public static function canAny(string ...$codes): bool {
        foreach ($codes as $code) {
            if (self::can($code)) return true;
        }
        return false;
    }

    public static function require(string $code): void {
        if (!self::can($code)) {
            http_response_code(403);
            exit('Accès refusé. Permission requise : ' . htmlspecialchars($code, ENT_QUOTES, 'UTF-8'));
        }
    }

    public static function requireAny(string ...$codes): void {
        if (!self::canAny(...$codes)) {
            http_response_code(403);
            exit('Accès refusé. Aucune permission d’administration AXIOM disponible.');
        }
    }

    public static function requireSuperAdmin(): void {
        if (!self::isSuperAdmin()) {
            http_response_code(403);
            exit('Accès réservé au super-administrateur.');
        }
    }
}
