<?php

namespace App\Domain\Manga\Domain\Model;

use App\Domain\Manga\Domain\Model\ValueObject\ExternalId;
use App\Domain\Manga\Domain\Model\ValueObject\ImageUrls;
use App\Domain\Manga\Domain\Model\ValueObject\MangaId;
use App\Domain\Manga\Domain\Model\ValueObject\MangaSlug;
use App\Domain\Manga\Domain\Model\ValueObject\MangaTitle;
use App\Domain\Manga\Domain\Model\ValueObject\MonitoringStatus;
use App\Domain\Shared\Domain\Model\AggregateRoot;
use DateTimeImmutable;

final class Manga extends AggregateRoot
{
    /** @var Chapter[] */
    private array $newChapters = [];

    /** @var array<string, Chapter> */
    private array $modifiedChapters = [];

    /** @var Chapter[] */
    private array $chaptersToDelete = [];

    public function __construct(
        private MangaId     $id,
        private MangaTitle  $title,
        private MangaSlug   $slug,
        private string      $description,
        private string      $author,
        private int         $publicationYear,
        private array       $genres,
        private string      $status,
        private ?ExternalId $externalId = null,
        private ?string     $imageUrl = null,
        private ?float      $rating = null,
        private ?ImageUrls  $imageUrls = null,
        private array       $alternativeSlugs = [],
        private ?DateTimeImmutable  $createdAt = null,
        private ?MonitoringStatus $monitoringStatus = null,
        private ?DateTimeImmutable $lastMonitoringCheck = null,
    ) {
        $this->monitoringStatus = $this->monitoringStatus ?? MonitoringStatus::disabled();
    }

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

    public function getTitle(): MangaTitle
    {
        return $this->title;
    }

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

    public function getDescription(): string
    {
        return $this->description;
    }

    public function getAuthor(): string
    {
        return $this->author;
    }

    public function getPublicationYear(): int
    {
        return $this->publicationYear;
    }

    public function getGenres(): array
    {
        return $this->genres;
    }

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

    public function getExternalId(): ?ExternalId
    {
        return $this->externalId;
    }

    public function getImageUrl(): ?string
    {
        return $this->imageUrl;
    }

    public function getRating(): ?float
    {
        return $this->rating;
    }

    public function getImageUrls(): ?ImageUrls
    {
        return $this->imageUrls;
    }

    public function setRating(float $rating): void
    {
        $this->rating = $rating;
    }

    public function updateId(MangaId $id): void
    {
        $this->id = $id;
    }

    public function updateImageUrls(ImageUrls $imageUrls): void
    {
        $this->imageUrls = $imageUrls;
    }

    public function getAlternativeSlugs(): array
    {
        return $this->alternativeSlugs;
    }

    public function updateTitle(MangaTitle $title): void
    {
        $this->title = $title;
    }

    public function updateDescription(string $description): void
    {
        $this->description = $description;
    }

    public function updateAuthor(string $author): void
    {
        $this->author = $author;
    }

    public function updatePublicationYear(int $publicationYear): void
    {
        $this->publicationYear = $publicationYear;
    }

    public function updateGenres(array $genres): void
    {
        $this->genres = $genres;
    }

    public function updateStatus(string $status): void
    {
        $this->status = $status;
    }

    public function updateAlternativeSlugs(array $alternativeSlugs): void
    {
        $this->alternativeSlugs = $alternativeSlugs;
    }

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

    public function getMonitoringStatus(): MonitoringStatus
    {
        return $this->monitoringStatus;
    }

    public function isMonitoringEnabled(): bool
    {
        return $this->monitoringStatus->isEnabled();
    }

    public function isMonitored(): bool
    {
        return $this->monitoringStatus->isEnabled();
    }

    public function enableMonitoring(): void
    {
        $this->monitoringStatus = MonitoringStatus::enabled();
        $this->lastMonitoringCheck = new DateTimeImmutable();
    }

    public function disableMonitoring(): void
    {
        $this->monitoringStatus = MonitoringStatus::disabled();
        $this->lastMonitoringCheck = null;
    }

    public function getLastMonitoringCheck(): ?DateTimeImmutable
    {
        return $this->lastMonitoringCheck;
    }

    public function updateLastMonitoringCheck(DateTimeImmutable $lastMonitoringCheck): void
    {
        $this->lastMonitoringCheck = $lastMonitoringCheck;
    }

    public function addChapter(Chapter $chapter): void
    {
        $this->newChapters[] = $chapter;
    }

    public function updateChapterTitle(Chapter $chapter, ?string $title): void
    {
        $chapter->updateTitle($title);
        $this->modifiedChapters[$chapter->getId()] = $chapter;
    }

    public function updateChapterVolume(Chapter $chapter, ?int $volume): void
    {
        $chapter->updateVolume($volume);
        $this->modifiedChapters[$chapter->getId()] = $chapter;
    }

    public function updateChapterPages(Chapter $chapter, ?string $pagesDirectory, int $pageCount = 0): void
    {
        $chapter->updatePagesDirectory($pagesDirectory, $pageCount);
        $this->modifiedChapters[$chapter->getId()] = $chapter;
    }

    public function hideChapter(Chapter $chapter): void
    {
        $chapter->hide();
        $this->modifiedChapters[$chapter->getId()] = $chapter;
    }

    public function removeChapterPages(Chapter $chapter): void
    {
        $chapter->updatePagesDirectory(null, 0);
        $this->modifiedChapters[$chapter->getId()] = $chapter;
    }

    /** @return Chapter[] */
    public function pullNewChapters(): array
    {
        $chapters = $this->newChapters;
        $this->newChapters = [];

        return $chapters;
    }

    /** @return Chapter[] */
    public function pullModifiedChapters(): array
    {
        $chapters = array_values($this->modifiedChapters);
        $this->modifiedChapters = [];

        return $chapters;
    }

    /** @return Chapter[] */
    public function pullChaptersToDelete(): array
    {
        $chapters = $this->chaptersToDelete;
        $this->chaptersToDelete = [];

        return $chapters;
    }
}
