<?php

declare(strict_types=1);

namespace App\Application\LiveComponents\Dashboard;

use App\Framework\Core\ValueObjects\Timestamp;
use App\Framework\LiveComponents\Attributes\Action;
use App\Framework\LiveComponents\Attributes\LiveComponent;
use App\Framework\LiveComponents\Contracts\LiveComponentContract;
use App\Framework\LiveComponents\Contracts\Pollable;
use App\Framework\LiveComponents\ValueObjects\ComponentId;
use App\Framework\LiveComponents\ValueObjects\ComponentRenderData;
use App\Framework\Scheduler\Services\SchedulerService;

/**
 * Scheduler Timeline LiveComponent
 *
 * Displays scheduled tasks timeline:
 * - Total scheduled tasks count
 * - Tasks due for execution
 * - Upcoming tasks with next run time
 * - Execution statistics
 *
 * Polls every 30 seconds (scheduler state changes less frequently).
 */
#[LiveComponent('scheduler-timeline')]
final readonly class SchedulerTimelineComponent implements LiveComponentContract, Pollable
{
    private const MAX_UPCOMING_TASKS = 10;

    public function __construct(
        public ComponentId $id,
        public SchedulerState $state,
        private SchedulerService $scheduler
    ) {}

    public function getRenderData(): ComponentRenderData
    {
        // Initial poll if state is empty (lastUpdated is empty string)
        $state = $this->state->lastUpdated === ''
            ? $this->poll()
            : $this->state;

        return new ComponentRenderData(
            templatePath: 'livecomponent-scheduler-timeline',
            data: [
                // LiveComponent integration
                'componentId' => $this->id->toString(),
                'stateJson' => json_encode($state->toArray()),
                'pollInterval' => $this->getPollInterval(),

                // Component data
                'totalScheduledTasks' => $state->totalScheduledTasks,
                'dueTasks' => $state->dueTasks,
                'upcomingTasks' => $state->upcomingTasks,
                'nextExecution' => $state->nextExecution,
                'statistics' => $state->statistics,
                'lastUpdated' => $state->lastUpdated,
            ]
        );
    }

    #[Action]
    public function poll(): SchedulerState
    {
        $now = Timestamp::now();

        // Get all scheduled tasks
        $allTasks = $this->scheduler->getScheduledTasks();
        $totalScheduledTasks = count($allTasks);

        // Get due tasks
        $dueTasks = $this->scheduler->getDueTasks($now);
        $dueTasksCount = count($dueTasks);

        // Get next execution time
        $nextExecution = $this->scheduler->getNextExecution();
        $nextExecutionStr = $nextExecution?->format('Y-m-d H:i:s') ?? 'No tasks scheduled';

        // Get statistics
        $statistics = $this->scheduler->getStats();

        // Build upcoming tasks list (sorted by next execution)
        $upcomingTasks = [];
        foreach ($allTasks as $task) {
            $nextRun = $task->schedule->getNextRun($now);

            if ($nextRun !== null) {
                $timeUntil = $this->formatTimeUntil($now, $nextRun);
                $scheduleType = $this->getScheduleType($task->schedule);

                $upcomingTasks[] = [
                    'id' => $task->id,
                    'nextRun' => $nextRun->format('Y-m-d H:i:s'),
                    'nextRunRelative' => $timeUntil,
                    'scheduleType' => $scheduleType,
                    'isDue' => $nextRun->isBefore($now) || $nextRun->equals($now),
                ];
            }
        }

        // Sort by next run time and limit
        usort($upcomingTasks, fn($a, $b) => strcmp($a['nextRun'], $b['nextRun']));
        $upcomingTasks = array_slice($upcomingTasks, 0, self::MAX_UPCOMING_TASKS);

        return $this->state->withSchedulerData(
            totalScheduledTasks: $totalScheduledTasks,
            dueTasks: $dueTasksCount,
            upcomingTasks: $upcomingTasks,
            nextExecution: $nextExecutionStr,
            statistics: $statistics
        );
    }

    public function getPollInterval(): int
    {
        return 30000; // Poll every 30 seconds (scheduler changes less frequently)
    }

    /**
     * Format time until next execution in human-readable format
     */
    private function formatTimeUntil(Timestamp $now, Timestamp $nextRun): string
    {
        $diff = $nextRun->getTimestamp() - $now->getTimestamp();

        if ($diff < 0) {
            return 'Overdue';
        }

        if ($diff < 60) {
            return 'Less than 1 minute';
        }

        if ($diff < 3600) {
            $minutes = (int) ($diff / 60);
            return "{$minutes} minute" . ($minutes > 1 ? 's' : '');
        }

        if ($diff < 86400) {
            $hours = (int) ($diff / 3600);
            $minutes = (int) (($diff % 3600) / 60);
            $result = "{$hours} hour" . ($hours > 1 ? 's' : '');
            if ($minutes > 0) {
                $result .= ", {$minutes} min";
            }
            return $result;
        }

        $days = (int) ($diff / 86400);
        $hours = (int) (($diff % 86400) / 3600);
        $result = "{$days} day" . ($days > 1 ? 's' : '');
        if ($hours > 0) {
            $result .= ", {$hours} hour" . ($hours > 1 ? 's' : '');
        }
        return $result;
    }

    /**
     * Get human-readable schedule type
     */
    private function getScheduleType($schedule): string
    {
        $className = get_class($schedule);
        $shortName = substr($className, strrpos($className, '\\') + 1);

        return match ($shortName) {
            'CronSchedule' => 'Cron',
            'IntervalSchedule' => 'Interval',
            'OneTimeSchedule' => 'One-Time',
            'ManualSchedule' => 'Manual',
            default => $shortName
        };
    }
}
