<?php

declare(strict_types=1);

namespace App\Entity;

use App\Repository\TurnRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Uid\Uuid;

#[ORM\Entity(repositoryClass: TurnRepository::class)]
#[ORM\UniqueConstraint(name: 'uniq_turn_number_per_game', columns: ['game_id', 'turn_number'])]
#[ORM\HasLifecycleCallbacks]
class Turn
{
    #[ORM\Id]
    #[ORM\Column(type: Types::GUID, unique: true)]
    private string $id;

    #[ORM\ManyToOne(inversedBy: 'turns')]
    #[ORM\JoinColumn(nullable: false)]
    private Game $game;

    #[ORM\ManyToOne(inversedBy: 'turns')]
    #[ORM\JoinColumn(nullable: false)]
    private GamePlayer $player;

    #[ORM\Column]
    private int $turnNumber;

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

    #[ORM\Column]
    private int $startScore;

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

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

    #[ORM\Column]
    private bool $isBust = false;

    #[ORM\Column(type: Types::DATETIME_IMMUTABLE)]
    private \DateTimeImmutable $startedAt;

    #[ORM\Column(type: Types::DATETIME_IMMUTABLE, nullable: true)]
    private ?\DateTimeImmutable $endedAt = null;

    #[ORM\OneToMany(mappedBy: 'turn', targetEntity: DartThrow::class, cascade: ['persist', 'remove'], orphanRemoval: true)]
    #[ORM\OrderBy(['dartIndex' => 'ASC'])]
    private Collection $throws;

    public function __construct(Game $game, GamePlayer $player, int $turnNumber, ?int $playerTurnIndex, int $startScore)
    {
        $this->id = Uuid::v7()->toRfc4122();
        $this->game = $game;
        $this->player = $player;
        $this->turnNumber = $turnNumber;
        $this->playerTurnIndex = $playerTurnIndex;
        $this->startScore = $startScore;
        $this->startedAt = new \DateTimeImmutable();
        $this->throws = new ArrayCollection();
    }

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

    public function getGame(): Game
    {
        return $this->game;
    }

    public function setGame(Game $game): self
    {
        $this->game = $game;

        return $this;
    }

    public function getPlayer(): GamePlayer
    {
        return $this->player;
    }

    public function setPlayer(GamePlayer $player): self
    {
        $this->player = $player;

        return $this;
    }

    public function getTurnNumber(): int
    {
        return $this->turnNumber;
    }

    public function setTurnNumber(int $turnNumber): self
    {
        $this->turnNumber = $turnNumber;

        return $this;
    }

    public function getPlayerTurnIndex(): ?int
    {
        return $this->playerTurnIndex;
    }

    public function setPlayerTurnIndex(?int $playerTurnIndex): self
    {
        $this->playerTurnIndex = $playerTurnIndex;

        return $this;
    }

    public function getStartScore(): int
    {
        return $this->startScore;
    }

    public function setStartScore(int $startScore): self
    {
        $this->startScore = $startScore;

        return $this;
    }

    public function getEndScore(): ?int
    {
        return $this->endScore;
    }

    public function setEndScore(?int $endScore): self
    {
        $this->endScore = $endScore;

        return $this;
    }

    public function getTotalScored(): int
    {
        return $this->totalScored;
    }

    public function setTotalScored(int $totalScored): self
    {
        $this->totalScored = $totalScored;

        return $this;
    }

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

    public function setIsBust(bool $isBust): self
    {
        $this->isBust = $isBust;

        return $this;
    }

    public function getStartedAt(): \DateTimeImmutable
    {
        return $this->startedAt;
    }

    public function setStartedAt(\DateTimeImmutable $startedAt): self
    {
        $this->startedAt = $startedAt;

        return $this;
    }

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

    public function setEndedAt(?\DateTimeImmutable $endedAt): self
    {
        $this->endedAt = $endedAt;

        return $this;
    }

    /** @return Collection<int, DartThrow> */
    public function getThrows(): Collection
    {
        return $this->throws;
    }

    public function addThrow(DartThrow $throw): self
    {
        if (!$this->throws->contains($throw)) {
            $this->throws->add($throw);
            $throw->setTurn($this);
        }

        return $this;
    }

    public function removeThrow(DartThrow $throw): self
    {
        $this->throws->removeElement($throw);

        return $this;
    }

    #[ORM\PrePersist]
    public function onPrePersist(): void
    {
        if (!isset($this->startedAt)) {
            $this->startedAt = new \DateTimeImmutable();
        }
    }
}
