<?php

declare(strict_types=1);

namespace App\Framework\Console\Progress;

use App\Framework\Console\ConsoleColor;
use App\Framework\Console\ConsoleOutputInterface;

/**
 * Spinner progress indicator for indeterminate operations
 */
final class SpinnerProgress implements ProgressInterface
{
    private const SPINNER_CHARS = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];

    private int $step = 0;

    private bool $finished = false;

    private ?string $currentTask = null;

    private float $startTime;

    public function __construct(
        private readonly ConsoleOutputInterface $output,
        private readonly string $title = 'Working'
    ) {
        $this->startTime = microtime(true);
        $this->render();
    }

    public function setTotal(int $total): void
    {
        // Spinner doesn't use total
    }

    public function advance(int $step = 1, ?string $task = null): void
    {
        if ($this->finished) {
            return;
        }

        $this->step += $step;
        if ($task !== null) {
            $this->currentTask = $task;
        }
        $this->render();
    }

    public function setProgress(int $current, ?string $task = null): void
    {
        if ($this->finished) {
            return;
        }

        $this->step = $current;
        if ($task !== null) {
            $this->currentTask = $task;
        }
        $this->render();
    }

    public function setTask(string $task): void
    {
        $this->currentTask = $task;
        $this->render();
    }

    public function getProgress(): float
    {
        return $this->finished ? 1.0 : 0.0;
    }

    public function finish(?string $message = null): void
    {
        if ($this->finished) {
            return;
        }

        $this->finished = true;
        $this->output->write("\r");

        if ($message) {
            $this->output->writeLine("✅ {$message}", ConsoleColor::GREEN);
        } else {
            $this->output->writeLine("✅ {$this->title} completed", ConsoleColor::GREEN);
        }
    }

    public function isFinished(): bool
    {
        return $this->finished;
    }

    private function render(): void
    {
        if ($this->finished) {
            return;
        }

        $spinner = self::SPINNER_CHARS[$this->step % count(self::SPINNER_CHARS)];
        $elapsed = $this->formatTime(microtime(true) - $this->startTime);

        $output = "{$spinner} {$this->title} ({$elapsed})";

        if ($this->currentTask) {
            $maxTaskLength = 40;
            $truncatedTask = strlen($this->currentTask) > $maxTaskLength
                ? substr($this->currentTask, 0, $maxTaskLength - 3) . '...'
                : $this->currentTask;
            $output .= " - {$truncatedTask}";
        }

        $this->output->write("\r{$output}", ConsoleColor::CYAN);
    }

    private function formatTime(float $seconds): string
    {
        $minutes = (int) ($seconds / 60);
        $seconds = (int) ($seconds % 60);

        return sprintf('%02d:%02d', $minutes, $seconds);
    }
}
