<?php

namespace App\Entity;

use App\Repository\ServiceRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;

#[ORM\Entity(repositoryClass: ServiceRepository::class)]
class Service
{
    public const STATUS_UP = 'up';
    public const STATUS_DEGRADED = 'degraded';
    public const STATUS_DOWN = 'down';
    public const STATUS_MAINTENANCE = 'maintenance';
    public const STATUS_SOON = 'soon';

    public const STATUSES = [
        self::STATUS_UP,
        self::STATUS_DEGRADED,
        self::STATUS_DOWN,
        self::STATUS_MAINTENANCE,
        self::STATUS_SOON,
    ];

    #[ORM\Id]
    #[ORM\GeneratedValue]
    #[ORM\Column]
    private ?int $id = null;

    #[ORM\Column(length: 255)]
    private string $name;

    #[ORM\Column(length: 50, unique: true)]
    private string $slug;

    #[ORM\Column(length: 500, nullable: true)]
    private ?string $url = null;

    #[ORM\ManyToOne(targetEntity: ServiceCategory::class, inversedBy: 'services')]
    #[ORM\JoinColumn(nullable: false, onDelete: 'CASCADE')]
    private ServiceCategory $category;

    #[ORM\Column(length: 20)]
    private string $status = self::STATUS_UP;

    #[ORM\Column(type: 'text', nullable: true)]
    private ?string $message = null;

    #[ORM\Column(options: ['default' => false])]
    private bool $isExternal = false;

    #[ORM\Column(length: 50, nullable: true)]
    private ?string $externalType = null;

    #[ORM\Column]
    private int $position = 0;

    /** @var Collection<int, ServiceStatusHistory> */
    #[ORM\OneToMany(targetEntity: ServiceStatusHistory::class, mappedBy: 'service', cascade: ['persist', 'remove'], orphanRemoval: true)]
    #[ORM\OrderBy(['createdAt' => 'DESC'])]
    private Collection $statusHistory;

    #[ORM\Column]
    private \DateTimeImmutable $createdAt;

    #[ORM\Column(nullable: true)]
    private ?\DateTimeImmutable $updatedAt = null;

    public function __construct(string $name, string $slug, ServiceCategory $category)
    {
        $this->name = $name;
        $this->slug = $slug;
        $this->category = $category;
        $this->statusHistory = new ArrayCollection();
        $this->createdAt = new \DateTimeImmutable();
    }

    public function getId(): ?int
    {
        return $this->id;
    }

    public function getName(): string
    {
        return $this->name;
    }

    public function setName(string $name): static
    {
        $this->name = $name;

        return $this;
    }

    public function getSlug(): string
    {
        return $this->slug;
    }

    public function getUrl(): ?string
    {
        return $this->url;
    }

    public function setUrl(?string $url): static
    {
        $this->url = $url;

        return $this;
    }

    public function getCategory(): ServiceCategory
    {
        return $this->category;
    }

    public function getStatus(): string
    {
        return $this->status;
    }

    public function setStatus(string $status, ?string $message = null): static
    {
        $oldStatus = $this->status;
        $this->status = $status;
        $this->message = $message;
        $this->updatedAt = new \DateTimeImmutable();

        if ($oldStatus !== $status) {
            $this->addStatusHistory($status, $message);
        }

        return $this;
    }

    public function getMessage(): ?string
    {
        return $this->message;
    }

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

    public function setIsExternal(bool $isExternal): static
    {
        $this->isExternal = $isExternal;

        return $this;
    }

    public function getExternalType(): ?string
    {
        return $this->externalType;
    }

    public function setExternalType(?string $externalType): static
    {
        $this->externalType = $externalType;

        return $this;
    }

    public function getPosition(): int
    {
        return $this->position;
    }

    public function setPosition(int $position): static
    {
        $this->position = $position;

        return $this;
    }

    /** @return Collection<int, ServiceStatusHistory> */
    public function getStatusHistory(): Collection
    {
        return $this->statusHistory;
    }

    public function getCreatedAt(): \DateTimeImmutable
    {
        return $this->createdAt;
    }

    public function getUpdatedAt(): ?\DateTimeImmutable
    {
        return $this->updatedAt;
    }

    private function addStatusHistory(string $status, ?string $message): void
    {
        $history = new ServiceStatusHistory($this, $status, $message);
        $this->statusHistory->add($history);
    }

    /**
     * Calcule le ratio d'uptime sur les N derniers jours.
     *
     * @param list<ServiceStatusHistory> $history
     */
    public function computeUptimeRatio(array $history, int $days = 30): float
    {
        if ([] === $history) {
            return 'up' === $this->status ? 100.0 : 0.0;
        }

        $now = new \DateTimeImmutable();
        $start = $now->modify('-'.$days.' days');
        $totalSeconds = $days * 86400;
        $downSeconds = 0;
        $lastTimestamp = $now;
        $downStatuses = [self::STATUS_DOWN, self::STATUS_MAINTENANCE];

        foreach ($history as $entry) {
            $entryDate = $entry->getCreatedAt();
            if ($entryDate < $start) {
                $entryDate = $start;
            }

            if (\in_array($entry->getStatus(), $downStatuses, true)) {
                $downSeconds += $lastTimestamp->getTimestamp() - $entryDate->getTimestamp();
            }

            $lastTimestamp = $entryDate;
        }

        $upSeconds = $totalSeconds - $downSeconds;

        return round(max(0, min(100, ($upSeconds / $totalSeconds) * 100)), 2);
    }
}
