<?php

namespace MintyPHP\App\Module;

use MintyPHP\Repository\Access\PermissionRepositoryInterface;

/**
 * Synchronizes module-defined permissions into the permissions table.
 */
final class ModulePermissionSynchronizer
{
    public function __construct(
        private readonly ModuleRegistry $moduleRegistry,
        private readonly PermissionRepositoryInterface $permissionRepository
    ) {
    }

    /**
     * @return array{created: int, updated: int, unchanged: int, total: int}
     */
    public function sync(): array
    {
        $created = 0;
        $updated = 0;
        $unchanged = 0;
        $total = 0;

        foreach ($this->moduleRegistry->getPermissions() as $permissionDefinition) {
            $total++;
            $key = trim((string) $permissionDefinition['key']);
            if ($key === '') {
                throw new \RuntimeException('Module permission definition has empty key.');
            }

            $desired = [
                'key' => $key,
                'description' => trim((string) $permissionDefinition['description']),
                'active' => (int) $permissionDefinition['active'],
                'is_system' => (int) $permissionDefinition['is_system'],
            ];

            $existing = $this->permissionRepository->findByKey($key);
            if (!is_array($existing)) {
                $createdId = $this->permissionRepository->create($desired);
                if ($createdId === null) {
                    throw new \RuntimeException("Failed to create module permission '{$key}'.");
                }
                $created++;
                continue;
            }

            $existingId = (int) ($existing['id'] ?? 0);
            if ($existingId <= 0) {
                throw new \RuntimeException("Permission '{$key}' exists without a valid id.");
            }

            if ($this->isPermissionEqual($existing, $desired)) {
                $unchanged++;
                continue;
            }

            $wasUpdated = $this->permissionRepository->update($existingId, $desired);
            if (!$wasUpdated) {
                throw new \RuntimeException("Failed to update module permission '{$key}' (id {$existingId}).");
            }
            $updated++;
        }

        return [
            'created' => $created,
            'updated' => $updated,
            'unchanged' => $unchanged,
            'total' => $total,
        ];
    }

    /**
     * @param array<string, mixed> $existing
     * @param array<string, mixed> $desired
     */
    private function isPermissionEqual(array $existing, array $desired): bool
    {
        $existingDescription = trim((string) ($existing['description'] ?? ''));
        $existingActive = (int) ($existing['active'] ?? 0);
        $existingSystem = (int) ($existing['is_system'] ?? 0);

        return $existingDescription === (string) ($desired['description'] ?? '')
            && $existingActive === (int) ($desired['active'] ?? 0)
            && $existingSystem === (int) ($desired['is_system'] ?? 0);
    }
}
