<?php

require_once __DIR__ . '/../../core/database.php';
require_once __DIR__ . '/DashboardAccessService.php';

class DashboardUserAccessAdminService
{
    private $pdo;
    private $accessService;
    private $catalog;

    public function __construct(?PDO $pdo = null)
    {
        $this->pdo = $pdo ?: db();
        $this->accessService = new DashboardAccessService();
        $this->catalog = $this->accessService->catalog();
    }

    public function catalog()
    {
        return $this->catalog;
    }

    public function getAccessMatrix($userId, $role)
    {
        $matrix = $this->emptyMatrix();
        $userId = (int)$userId;
        $rows = array();

        if ($userId > 0) {
            $stmt = $this->pdo->prepare('SELECT dashboard_key,can_view,can_configure,can_export FROM dashboard_user_access WHERE user_id=?');
            $stmt->execute(array($userId));
            $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
        }

        if (empty($rows)) return $this->defaultsForRole($role);

        foreach ($rows as $row) {
            $key = (string)$row['dashboard_key'];
            if (!isset($matrix[$key])) continue;
            $matrix[$key] = array(
                'view' => (int)$row['can_view'] === 1,
                'configure' => (int)$row['can_configure'] === 1,
                'export' => (int)$row['can_export'] === 1,
            );
        }

        if ($role === 'admin') return $this->allEnabledMatrix();
        return $matrix;
    }

    public function defaultsForRole($role)
    {
        if ($role === 'admin') return $this->allEnabledMatrix();

        $matrix = $this->emptyMatrix();
        $allowed = $this->accessService->allowedDashboards(array('id' => 0, 'role' => $role, 'area' => null));
        foreach ($allowed as $key) {
            if (isset($matrix[$key])) $matrix[$key]['view'] = true;
        }
        return $matrix;
    }

    public function saveAccessMatrix($userId, $role, $postedAccess, $actorUserId, $previousRole = null)
    {
        $userId = (int)$userId;
        $actorUserId = (int)$actorUserId;
        if ($userId <= 0 || $actorUserId <= 0) {
            throw new InvalidArgumentException('Usuario inválido para asignar permisos de dashboard.');
        }

        $before = $this->getAccessMatrix($userId, $previousRole !== null ? $previousRole : $role);
        $after = $this->normalizePostedAccess($role, is_array($postedAccess) ? $postedAccess : array());
        $stmt = $this->pdo->prepare("INSERT INTO dashboard_user_access
            (user_id,dashboard_key,can_view,can_configure,can_export,granted_by_user_id)
            VALUES (?,?,?,?,?,?)
            ON DUPLICATE KEY UPDATE
                can_view=VALUES(can_view),
                can_configure=VALUES(can_configure),
                can_export=VALUES(can_export),
                granted_by_user_id=VALUES(granted_by_user_id)");

        foreach ($after as $key => $permissions) {
            $stmt->execute(array(
                $userId,
                $key,
                $permissions['view'] ? 1 : 0,
                $permissions['configure'] ? 1 : 0,
                $permissions['export'] ? 1 : 0,
                $actorUserId,
            ));
        }

        $this->insertAudit($userId, $actorUserId, $before, $after);
        return $after;
    }

    public function deleteAccessForUser($userId)
    {
        $stmt = $this->pdo->prepare('DELETE FROM dashboard_user_access WHERE user_id=?');
        $stmt->execute(array((int)$userId));
    }

    private function normalizePostedAccess($role, array $postedAccess)
    {
        if ($role === 'admin') return $this->allEnabledMatrix();

        $matrix = $this->emptyMatrix();
        foreach ($matrix as $key => $permissions) {
            $posted = isset($postedAccess[$key]) && is_array($postedAccess[$key]) ? $postedAccess[$key] : array();
            $canConfigure = !empty($posted['configure']);
            $canExport = !empty($posted['export']);
            $canView = !empty($posted['view']) || $canConfigure || $canExport;
            $matrix[$key] = array(
                'view' => $canView,
                'configure' => $canConfigure && $canView,
                'export' => $canExport && $canView,
            );
        }
        return $matrix;
    }

    private function emptyMatrix()
    {
        $matrix = array();
        foreach ($this->catalog as $key => $dashboard) {
            $matrix[$key] = array('view' => false, 'configure' => false, 'export' => false);
        }
        return $matrix;
    }

    private function allEnabledMatrix()
    {
        $matrix = $this->emptyMatrix();
        foreach ($matrix as $key => $permissions) {
            $matrix[$key] = array('view' => true, 'configure' => true, 'export' => true);
        }
        return $matrix;
    }

    private function insertAudit($userId, $actorUserId, array $before, array $after)
    {
        $remoteAddress = isset($_SERVER['REMOTE_ADDR']) ? substr((string)$_SERVER['REMOTE_ADDR'], 0, 64) : null;
        $sessionKey = session_status() === PHP_SESSION_ACTIVE && session_id() !== '' ? hash('sha256', session_id()) : null;
        $stmt = $this->pdo->prepare("INSERT INTO dashboard_audit_log
            (user_id,action_key,dashboard_key,entity_type,entity_id,before_json,after_json,ip_address,session_key)
            VALUES (?,?,?,?,?,?,?,?,?)");
        $stmt->execute(array(
            $actorUserId,
            'dashboard.permissions.updated',
            null,
            'dashboard_user_access',
            (string)$userId,
            json_encode($before, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES),
            json_encode($after, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES),
            $remoteAddress,
            $sessionKey,
        ));
    }
}
