<?php
/**
 * Route for self-serve config draft/publish lifecycle
 */

namespace routes;

use classes\authentication;
use modules\selfserve\classes\selfserve_config_versioning;
use objects\logs_o;
use traits\route_t;

class departmentSelfserveConfigVersionsRoute
{
    use route_t;

    public function run(): void
    {
        $this->get('/department/selfserve/config/versions', function () {
            global $response;
            $this->requirePermission('list_department_selfserve_config_versions');
            $user = (new authentication())->get_user();
            if (!$user) {
                $response->error('Invalid session', 400);
            }

            self::requireParameters(['department']);
            $departmentId = (int)self::getParameter('department');
            $authorizedDepartmentIds = $user->getGroup()->getDepartments();
            if (!in_array($departmentId, $authorizedDepartmentIds, true) && !$this->hasPermission('view_all_department_selfserve_config_versions')) {
                $this->forbidDepartmentAccess($departmentId, ['view_all_department_selfserve_config_versions']);
            }

            $service = new selfserve_config_versioning();
            $versions = $service->listVersions($departmentId);
            (new logs_o())->add('selfserve_config_versions', $departmentId, 1, $user->id, 'LIST_CONFIG_VERSIONS', 'User listed self-serve config versions');
            $response->success($versions);
        }, [
            'list_department_selfserve_config_versions' => 'List self-serve config versions for a department',
            'view_all_department_selfserve_config_versions' => 'List self-serve config versions across all departments',
        ]);

        $this->get('/department/selfserve/config/history', function () {
            global $response;
            $this->requirePermission('list_department_selfserve_config_versions');
            $user = (new authentication())->get_user();
            if (!$user) {
                $response->error('Invalid session', 400);
            }

            self::requireParameters(['department']);
            $departmentId = (int)self::getParameter('department');
            $authorizedDepartmentIds = $user->getGroup()->getDepartments();
            if (!in_array($departmentId, $authorizedDepartmentIds, true) && !$this->hasPermission('view_all_department_selfserve_config_versions')) {
                $this->forbidDepartmentAccess($departmentId, ['view_all_department_selfserve_config_versions']);
            }

            $service = new selfserve_config_versioning();
            $response->success($service->listVersions($departmentId));
        }, [
            'list_department_selfserve_config_versions' => 'List self-serve config history for a department',
            'view_all_department_selfserve_config_versions' => 'List self-serve config history across all departments',
        ]);

        $this->get('/department/selfserve/config/active', function () {
            global $response;
            $this->requirePermission('list_department_selfserve_config_versions');
            $user = (new authentication())->get_user();
            if (!$user) {
                $response->error('Invalid session', 400);
            }

            self::requireParameters(['department']);
            $departmentId = (int)self::getParameter('department');
            $authorizedDepartmentIds = $user->getGroup()->getDepartments();
            if (!in_array($departmentId, $authorizedDepartmentIds, true) && !$this->hasPermission('view_all_department_selfserve_config_versions')) {
                $this->forbidDepartmentAccess($departmentId, ['view_all_department_selfserve_config_versions']);
            }

            $service = new selfserve_config_versioning();
            $published = $service->getPublishedConfig($departmentId);
            if ($published === null) {
                $response->success([
                    'version_id' => null,
                    'config' => null,
                    'source' => 'legacy',
                ]);
            }

            $response->success([
                'version_id' => (int)$published['version_id'],
                'config' => (array)$published['config'],
                'source' => 'published',
            ]);
        }, [
            'list_department_selfserve_config_versions' => 'View active self-serve config version for a department',
            'view_all_department_selfserve_config_versions' => 'View active self-serve config version across all departments',
        ]);

        $this->post('/department/selfserve/config/draft', function () {
            global $response;
            $this->requirePermission('edit_department_selfserve_config_versions');
            $user = (new authentication())->get_user();
            if (!$user) {
                $response->error('Invalid session', 400);
            }

            self::requireParameters(['department']);
            $departmentId = (int)self::getParameter('department');
            $this->assertDepartmentAccess($user, $departmentId);

            $forceRefresh = self::isParametersSet(['force'])
                ? filter_var(self::getParameter('force'), FILTER_VALIDATE_BOOLEAN)
                : false;

            $service = new selfserve_config_versioning();
            $draft = $service->ensureDraftFromLegacy($departmentId, (int)$user->id, $forceRefresh === true);
            (new logs_o())->add('selfserve_config_versions', $departmentId, 1, $user->id, 'UPSERT_CONFIG_DRAFT', 'User upserted self-serve config draft');
            $response->success($draft);
        }, [
            'edit_department_selfserve_config_versions' => 'Create or update a self-serve config draft for a department',
        ]);

        $this->post('/department/selfserve/config/validate', function () {
            global $response;
            $this->requirePermission('edit_department_selfserve_config_versions');
            $user = (new authentication())->get_user();
            if (!$user) {
                $response->error('Invalid session', 400);
            }

            self::requireParameters(['department']);
            $departmentId = (int)self::getParameter('department');
            $this->assertDepartmentAccess($user, $departmentId);

            $service = new selfserve_config_versioning();
            $validation = $service->validateDraft($departmentId);
            (new logs_o())->add('selfserve_config_versions', $departmentId, 1, $user->id, 'VALIDATE_CONFIG_DRAFT', 'User validated self-serve config draft');
            $response->success($validation);
        }, [
            'edit_department_selfserve_config_versions' => 'Validate a self-serve config draft for a department',
        ]);

        $this->post('/department/selfserve/config/publish', function () {
            global $response;
            $this->requirePermission('publish_department_selfserve_config_versions');
            $user = (new authentication())->get_user();
            if (!$user) {
                $response->error('Invalid session', 400);
            }

            self::requireParameters(['department']);
            $departmentId = (int)self::getParameter('department');
            $this->assertDepartmentAccess($user, $departmentId);

            $service = new selfserve_config_versioning();
            try {
                $published = $service->publishDraft($departmentId, (int)$user->id);
                (new logs_o())->add('selfserve_config_versions', $departmentId, 1, $user->id, 'PUBLISH_CONFIG_DRAFT', 'User published self-serve config draft');
                $response->success($published);
            } catch (\RuntimeException $exception) {
                $response->error($exception->getMessage(), 422);
            }
        }, [
            'publish_department_selfserve_config_versions' => 'Publish self-serve config draft for a department',
        ]);

        $this->post('/department/selfserve/config/rollback', function () {
            global $response;
            $this->requirePermission('rollback_department_selfserve_config_versions');
            $user = (new authentication())->get_user();
            if (!$user) {
                $response->error('Invalid session', 400);
            }

            self::requireParameters(['department', 'target_version_id']);
            $departmentId = (int)self::getParameter('department');
            $targetVersionId = (int)self::getParameter('target_version_id');
            if ($targetVersionId <= 0) {
                $response->error('Invalid target_version_id', 400);
            }

            $this->assertDepartmentAccess($user, $departmentId);

            $service = new selfserve_config_versioning();
            try {
                $rolledBack = $service->rollbackToVersion($departmentId, $targetVersionId, (int)$user->id);
                (new logs_o())->add('selfserve_config_versions', $departmentId, 1, $user->id, 'ROLLBACK_CONFIG_VERSION', 'User rolled back self-serve config to version ' . $targetVersionId);
                $response->success($rolledBack);
            } catch (\RuntimeException $exception) {
                $response->error($exception->getMessage(), 422);
            }
        }, [
            'rollback_department_selfserve_config_versions' => 'Rollback self-serve config to a previous version for a department',
        ]);
    }

    private function assertDepartmentAccess(object $user, int $departmentId): void
    {
        $authorizedDepartmentIds = $user->getGroup()->getDepartments();
        if (!in_array($departmentId, $authorizedDepartmentIds, true)) {
            $this->forbidDepartmentAccess($departmentId);
        }
    }
}
