<?php
declare(strict_types=1);

namespace App\Modules\AccessMatrix\Services;

use App\Core\App;
use App\Core\Registries\PermissionRegistry;

final class MatrixService
{
    public static function buildMatrix(?array $roleIds = null): array
    {
        $db = App::getInstance()->db();

        $roleQuery = "SELECT id, role_code, name_ar, name_en, category, is_system, has_all_branches FROM roles WHERE is_active = 1";
        $roleParams = [];

        if ($roleIds) {
            $placeholders = implode(',', array_fill(0, count($roleIds), '?'));
            $roleQuery .= " AND id IN ({$placeholders})";
            $roleParams = $roleIds;
        }

        $roleQuery .= " ORDER BY `level` ASC, name_ar ASC";
        $roles = $db->select($roleQuery, $roleParams);

        $allPermissions = PermissionRegistry::getAllGrouped();

        $rolePermMap = [];
        foreach ($roles as $role) {
            $perms = $db->select(
                "SELECT permission_key FROM role_permissions WHERE role_id = ?",
                [(int) $role['id']]
            );
            $rolePermMap[(int) $role['id']] = array_column($perms, 'permission_key');
        }

        $matrix = [];
        foreach ($allPermissions as $group => $permissions) {
            $matrix[$group] = [
                'group'       => $group,
                'permissions' => [],
            ];

            foreach ($permissions as $key => $meta) {
                $row = [
                    'key'   => $key,
                    'label' => $meta['ar'] ?? $key,
                    'roles' => [],
                ];

                foreach ($roles as $role) {
                    $roleId = (int) $role['id'];
                    $hasWildcard = in_array('*', $rolePermMap[$roleId], true);
                    $hasPermission = $hasWildcard || in_array($key, $rolePermMap[$roleId], true);
                    $row['roles'][$roleId] = $hasPermission;
                }

                $matrix[$group]['permissions'][] = $row;
            }
        }

        return [
            'roles'  => $roles,
            'matrix' => $matrix,
        ];
    }

    public static function compareRoles(int $roleA, int $roleB): array
    {
        $db = App::getInstance()->db();

        $permsA = array_column(
            $db->select("SELECT permission_key FROM role_permissions WHERE role_id = ?", [$roleA]),
            'permission_key'
        );
        $permsB = array_column(
            $db->select("SELECT permission_key FROM role_permissions WHERE role_id = ?", [$roleB]),
            'permission_key'
        );

        $onlyA = array_diff($permsA, $permsB);
        $onlyB = array_diff($permsB, $permsA);
        $shared = array_intersect($permsA, $permsB);

        return [
            'only_a' => array_values($onlyA),
            'only_b' => array_values($onlyB),
            'shared'  => array_values($shared),
        ];
    }

    public static function cloneRole(int $sourceRoleId, string $newCode, string $nameAr, string $nameEn = ''): int
    {
        $db = App::getInstance()->db();

        $source = $db->selectOne("SELECT * FROM roles WHERE id = ?", [$sourceRoleId]);
        if (!$source) {
            throw new \RuntimeException('الدور المصدر غير موجود', 404);
        }

        $db->insert('roles', [
            'role_code'        => $newCode,
            'name_ar'          => $nameAr,
            'name_en'          => $nameEn ?: $source['name_en'],
            'description_ar'   => $source['description_ar'],
            'description_en'   => $source['description_en'] ?? null,
            'is_system'        => 0,
            'parent_role_id'   => $source['parent_role_id'],
            'has_all_branches' => (int) $source['has_all_branches'],
            'category'         => $source['category'],
            'level'            => (int) $source['level'],
            'is_template'      => 0,
            'is_active'        => 1,
            'created_at'       => date('Y-m-d H:i:s'),
            'updated_at'       => date('Y-m-d H:i:s'),
        ]);

        $newRole = $db->selectOne("SELECT id FROM roles WHERE role_code = ?", [$newCode]);
        $newRoleId = (int) $newRole['id'];

        $sourcePerms = $db->select("SELECT permission_key FROM role_permissions WHERE role_id = ?", [$sourceRoleId]);
        foreach ($sourcePerms as $perm) {
            $db->insert('role_permissions', [
                'role_id'        => $newRoleId,
                'permission_key' => $perm['permission_key'],
                'granted_at'     => date('Y-m-d H:i:s'),
            ]);
        }

        return $newRoleId;
    }

    public static function exportCsv(array $matrixData): string
    {
        $roles = $matrixData['roles'];
        $matrix = $matrixData['matrix'];

        $lines = [];

        $header = ['المجموعة', 'الصلاحية'];
        foreach ($roles as $role) {
            $header[] = $role['name_ar'] . ' (' . $role['role_code'] . ')';
        }
        $lines[] = implode(',', array_map(fn($v) => '"' . str_replace('"', '""', $v) . '"', $header));

        foreach ($matrix as $group => $groupData) {
            foreach ($groupData['permissions'] as $perm) {
                $row = [$group, $perm['label']];
                foreach ($roles as $role) {
                    $row[] = ($perm['roles'][(int) $role['id']] ?? false) ? '✓' : '';
                }
                $lines[] = implode(',', array_map(fn($v) => '"' . str_replace('"', '""', (string) $v) . '"', $row));
            }
        }

        return "\xEF\xBB\xBF" . implode("\n", $lines);
    }
}
