<?php

namespace routes;

use classes\authentication;
use classes\cron_scheduler;
use classes\cron_worker;
use classes\release_manager;
use objects\logs_o;
use Throwable;
use traits\route_t;

class cronRoute
{
    use route_t;

    public function run(): void
    {
        $this->get('/superuser/cron', function () {
            global $response;

            $this->requireClassicSuperuserPermission('superuser_cron_view');
            $response->success((new cron_scheduler())->listTasks());
        }, [
            'superuser_cron_view' => 'View cron task schedule, run status, estimates, and history',
        ]);

        $this->get('/superuser/cron/runs', function () {
            global $response;

            $this->requireClassicSuperuserPermission('superuser_cron_view');
            $task_id = $this->getParameter('task_id');
            $limit = (int)($this->getParameter('limit') ?? 50);
            $response->success([
                'runs' => (new cron_scheduler())->listRuns(is_string($task_id) ? $task_id : null, $limit),
            ]);
        }, [
            'superuser_cron_view' => 'View cron task schedule, run status, estimates, and history',
        ]);

        $this->get('/superuser/cron/workers', function () {
            global $response;

            $this->requireClassicSuperuserPermission('superuser_cron_view');
            $parameters = $this->getParametersAsArray();
            try {
                $response->success((new release_manager())->cronWorkerStatus($parameters));
            } catch (Throwable $throwable) {
                $workers = (new cron_worker())->listWorkers();
                $workers['deployment'] = [
                    'ok' => false,
                    'error' => $throwable->getMessage(),
                ];
                $workers['state'] = 'failed';
                $workers['issues'] = [[
                    'code' => 'status_load_failed',
                    'severity' => 'danger',
                    'message' => $throwable->getMessage(),
                ]];
                $response->success($workers);
            }
        }, [
            'superuser_cron_view' => 'View cron worker deployment and heartbeat state',
        ]);

        $this->post('/superuser/cron/workers/deploy', function () {
            global $response;

            $this->requireClassicSuperuserPermission('superuser_cron_manage');
            $this->requirePermission('superuser_coolify_manage');
            try {
                $result = (new release_manager())->deployCronWorker(
                    $this->getParametersAsArray(),
                    $this->actorUserId()
                );
                (new logs_o())->add('cron', 'global', 1, $this->actorUserId() ?? 0, 'CRON_WORKER_DEPLOY', 'Deployed cron worker');
                $response->success($result, 202);
            } catch (Throwable $throwable) {
                $response->error(['message' => $throwable->getMessage()], 409);
            }
        }, [
            'superuser_cron_manage' => 'Deploy and configure cron workers',
            'superuser_coolify_manage' => 'Deploy Coolify-managed infrastructure resources',
        ]);

        $this->post('/superuser/cron/run', function () {
            global $response;

            $this->requireClassicSuperuserPermission('SUPERUSER_RUN_CRON');
            $parameters = $this->getParametersAsArray();
            $task_id = trim((string)($parameters['task_id'] ?? ''));
            if ($task_id === '') {
                $response->error('Missing cron task id.', 400);
            }

            try {
                $run = (new cron_scheduler())->queueTaskRun(
                    $task_id,
                    $this->actorUserId(),
                    $this->toBool($parameters['force'] ?? false, false)
                );
                (new logs_o())->add('cron', 'global', 1, $this->actorUserId() ?? 0, 'CRON_JOB_QUEUED', 'Queued cron task: ' . $task_id);
                $response->success($run, 202);
            } catch (Throwable $throwable) {
                $response->error(['message' => $throwable->getMessage()], 409);
            }
        }, [
            'SUPERUSER_RUN_CRON' => 'Run cron jobs',
        ]);

        $this->patch('/superuser/cron/config', function () {
            global $response;

            $this->requireClassicSuperuserPermission('superuser_cron_manage');
            $parameters = $this->getParametersAsArray();
            $task_id = trim((string)($parameters['task_id'] ?? ''));
            if ($task_id === '') {
                $response->error('Missing cron task id.', 400);
            }

            try {
                $config = [];
                if (array_key_exists('enabled', $parameters)) {
                    $config['enabled'] = $this->toBool($parameters['enabled'], true);
                }
                if (array_key_exists('schedule', $parameters)) {
                    $config['schedule'] = $parameters['schedule'];
                }
                $result = (new cron_scheduler())->updateTaskConfig($task_id, $config);
                (new logs_o())->add('cron', 'global', 1, $this->actorUserId() ?? 0, 'CRON_TASK_CONFIG_UPDATED', 'Updated cron task: ' . $task_id);
                $response->success($result);
            } catch (Throwable $throwable) {
                $response->error(['message' => $throwable->getMessage()], 409);
            }
        }, [
            'superuser_cron_manage' => 'Configure cron task schedules and enabled state',
        ]);

        $this->post('/superuser/cron', function () {
            global $response;

            $this->requireClassicSuperuserPermission('SUPERUSER_RUN_CRON');
            $parameters = $this->getParametersAsArray();
            $scheduler = new cron_scheduler();

            try {
                if (isset($parameters['job']) && trim((string)$parameters['job']) !== '') {
                    $job = trim((string)$parameters['job']);
                    $run = $scheduler->runTask($job, 'manual', $this->actorUserId(), true);
                    (new logs_o())->add('cron', 'global', 1, $this->actorUserId() ?? 0, 'CRON_JOB_RUN', 'Ran cron job: ' . $job);
                    $response->success([
                        'message' => 'Cron job ran successfully',
                        'run' => $run,
                    ]);
                }

                $result = $scheduler->runDue('manual');
                (new logs_o())->add('cron', 'global', 1, $this->actorUserId() ?? 0, 'CRON_RUN', 'Ran due cron jobs');
                $response->success([
                    'message' => 'Due cron jobs ran successfully',
                    'data' => $result,
                ]);
            } catch (Throwable $throwable) {
                $response->error(['message' => $throwable->getMessage()], 409);
            }
        },
            [
                'SUPERUSER_RUN_CRON' => 'Run cron jobs'
            ]
        );
    }

    private function requireClassicSuperuserPermission(string $permission): bool
    {
        global $response;

        if ((new authentication())->get_subuser() !== false) {
            $response->error('Subuser sessions cannot manage cron tasks.', 403);
        }

        return $this->requirePermission($permission);
    }

    private function actorUserId(): ?int
    {
        try {
            $user = (new authentication())->get_user();
            return $user !== false && isset($user->id) ? (int)$user->id : null;
        } catch (Throwable) {
            return null;
        }
    }

    private function toBool(mixed $value, bool $default): bool
    {
        if (is_bool($value)) {
            return $value;
        }
        if ($value === null) {
            return $default;
        }
        $normalized = strtolower(trim((string)$value));
        if (in_array($normalized, ['1', 'true', 'yes', 'on'], true)) {
            return true;
        }
        if (in_array($normalized, ['0', 'false', 'no', 'off'], true)) {
            return false;
        }
        return $default;
    }
}
