<?php

declare(strict_types=1);

require dirname(__DIR__) . '/app/bootstrap.php';

use App\Core\Database;
use App\Services\DiarWorkspaceNavigation;

$branch = 'njch';
$backupArg = '';
foreach ($argv as $argument) {
    if (strpos($argument, '--backup=') === 0) {
        $backupArg = substr($argument, 9);
    }
}
$backupDir = dirname(__DIR__) . '/storage/diar6b-role-backups';
$matches = glob($backupDir . '/DIAR_6B_5_R2_7_1_roles_*.json') ?: [];
rsort($matches, SORT_STRING);
$backupPath = $backupArg !== '' ? $backupArg : (string)($matches[0] ?? '');

function rollbackOutput(array $payload, int $code = 0): void
{
    echo json_encode($payload, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), PHP_EOL;
    exit($code);
}

try {
    if ($backupPath === '' || !is_file($backupPath)) {
        throw new RuntimeException('ROLE_TEMPLATE_BACKUP_NOT_FOUND');
    }
    $backup = json_decode((string)file_get_contents($backupPath), true);
    if (!is_array($backup) || !is_array($backup['roles'] ?? null)) {
        throw new RuntimeException('ROLE_TEMPLATE_BACKUP_INVALID');
    }

    foreach (array_keys((array)$backup['roles']) as $roleCode) {
        if (($backup['roles'][$roleCode] ?? null) === null) {
            $assigned = Database::fetchOne($branch, "SELECT COUNT(*) user_count
                FROM DASH_ACL_USER_ROLES
                WHERE ROLE_CODE=:role_code", ['role_code' => $roleCode]);
            if ((int)($assigned['user_count'] ?? 0) > 0) {
                throw new RuntimeException('ROLE_HAS_ASSIGNED_USERS:' . $roleCode);
            }
        }
    }

    $statements = [];
    foreach ((array)$backup['roles'] as $roleCode => $oldRole) {
        $statements[] = [
            'sql' => "DELETE FROM DASH_ACL_ROLE_OVERRIDES WHERE ROLE_CODE=:role_code",
            'params' => ['role_code' => $roleCode],
        ];

        if ($oldRole === null) {
            $statements[] = [
                'sql' => "DELETE FROM DASH_ACL_ROLES WHERE ROLE_CODE=:role_code",
                'params' => ['role_code' => $roleCode],
            ];
            continue;
        }

        $statements[] = [
            'sql' => "MERGE INTO DASH_ACL_ROLES t
                USING (SELECT :role_code role_code FROM dual) s
                ON (t.ROLE_CODE=s.role_code)
                WHEN MATCHED THEN UPDATE SET
                    ROLE_NAME_EN=:name_en,
                    ROLE_NAME_AR=:name_ar,
                    ROLE_DESCRIPTION_EN=:description_en,
                    ROLE_DESCRIPTION_AR=:description_ar,
                    POLICY_MODE=:policy_mode,
                    AUTO_INCLUDE_NEW=:auto_include_new,
                    ALL_BRANCHES=:all_branches,
                    IS_SYSTEM_ROLE=:is_system_role,
                    IS_PROTECTED=:is_protected,
                    IS_ACTIVE=:is_active,
                    UPDATED_BY=:updated_by,
                    UPDATED_AT=SYSDATE
                WHEN NOT MATCHED THEN INSERT (
                    ROLE_CODE,ROLE_NAME_EN,ROLE_NAME_AR,
                    ROLE_DESCRIPTION_EN,ROLE_DESCRIPTION_AR,
                    POLICY_MODE,AUTO_INCLUDE_NEW,ALL_BRANCHES,
                    IS_SYSTEM_ROLE,IS_PROTECTED,IS_ACTIVE,
                    UPDATED_BY,UPDATED_AT
                ) VALUES (
                    :role_code,:name_en,:name_ar,
                    :description_en,:description_ar,
                    :policy_mode,:auto_include_new,:all_branches,
                    :is_system_role,:is_protected,:is_active,
                    :updated_by,SYSDATE
                )",
            'params' => [
                'role_code' => $roleCode,
                'name_en' => (string)($oldRole['role_name_en'] ?? $roleCode),
                'name_ar' => (string)($oldRole['role_name_ar'] ?? ''),
                'description_en' => (string)($oldRole['role_description_en'] ?? ''),
                'description_ar' => (string)($oldRole['role_description_ar'] ?? ''),
                'policy_mode' => (string)($oldRole['policy_mode'] ?? 'EXPLICIT'),
                'auto_include_new' => (int)($oldRole['auto_include_new'] ?? 0),
                'all_branches' => (int)($oldRole['all_branches'] ?? 0),
                'is_system_role' => (int)($oldRole['is_system_role'] ?? 0),
                'is_protected' => (int)($oldRole['is_protected'] ?? 0),
                'is_active' => (int)($oldRole['is_active'] ?? 1),
                'updated_by' => 'DIAR6B5_R27_ROLE_ROLLBACK',
            ],
        ];

        foreach ((array)($backup['overrides'][$roleCode] ?? []) as $override) {
            $statements[] = [
                'sql' => "INSERT INTO DASH_ACL_ROLE_OVERRIDES (
                    ROLE_CODE,PERMISSION_CODE,EFFECT,UPDATED_BY,UPDATED_AT
                ) VALUES (
                    :role_code,:permission_code,:effect,:updated_by,SYSDATE
                )",
                'params' => [
                    'role_code' => $roleCode,
                    'permission_code' => (string)$override['permission_code'],
                    'effect' => (string)$override['effect'],
                    'updated_by' => 'DIAR6B5_R27_ROLE_ROLLBACK',
                ],
            ];
        }
    }

    Database::executeTransaction($branch, $statements);
    rollbackOutput([
        'result' => 'PASS',
        'release' => 'DIAR-6B.5-R2.7.1',
        'backup' => $backupPath,
        'restored_roles' => count((array)$backup['roles']),
        'user_assignments_changed' => 'NONE',
    ]);
} catch (Throwable $e) {
    rollbackOutput([
        'result' => 'FAIL',
        'release' => 'DIAR-6B.5-R2.7.1',
        'error' => preg_replace('/\s+/', ' ', $e->getMessage()),
    ], 52);
}
