<?php

declare(strict_types=1);

namespace App\Module\Absence\Domain\Entity;

use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Metadata\Get;
use ApiPlatform\Metadata\GetCollection;
use ApiPlatform\Metadata\Patch;
use App\Module\Absence\Domain\Enum\AbsenceType;
use App\Module\Absence\Infrastructure\Doctrine\DoctrineAbsencePolicyRepository;
use App\Shared\Domain\Contract\BlamableInterface;
use App\Shared\Domain\Contract\TimestampableInterface;
use App\Shared\Domain\Trait\TimestampableBlamableTrait;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Serializer\Attribute\Groups;

/**
 * Per-type configuration of absence rules. Overrides the legal defaults and
 * lets an admin tune days/year, days/event, notice period, etc.
 */
#[ApiResource(
    operations: [
        new GetCollection(
            paginationEnabled: false,
            security: "is_granted('ROLE_USER')",
        ),
        new Get(security: "is_granted('ROLE_USER')"),
        new Patch(security: "is_granted('ROLE_ADMIN')"),
    ],
    normalizationContext: ['groups' => ['absence_policy:read']],
    denormalizationContext: ['groups' => ['absence_policy:write']],
    order: ['type' => 'ASC'],
)]
#[ORM\Entity(repositoryClass: DoctrineAbsencePolicyRepository::class)]
#[ORM\Table(name: 'absence_policy')]
#[ORM\UniqueConstraint(name: 'uniq_absence_policy_type', columns: ['type'])]
class AbsencePolicy implements TimestampableInterface, BlamableInterface
{
    use TimestampableBlamableTrait;

    #[ORM\Id]
    #[ORM\GeneratedValue]
    #[ORM\Column]
    #[Groups(['absence_policy:read'])]
    private ?int $id = null;

    #[ORM\Column(type: Types::STRING, length: 32, enumType: AbsenceType::class)]
    #[Groups(['absence_policy:read', 'absence_balance:read', 'absence_request:read'])]
    private AbsenceType $type;

    /** Yearly entitlement (e.g. 25 for paid leave); null when not relevant. */
    #[ORM\Column(type: Types::FLOAT, nullable: true)]
    #[Groups(['absence_policy:read', 'absence_policy:write'])]
    private ?float $daysPerYear = null;

    /** Days granted per event (e.g. 4 for marriage); null when not relevant. */
    #[ORM\Column(type: Types::FLOAT, nullable: true)]
    #[Groups(['absence_policy:read', 'absence_policy:write'])]
    private ?float $daysPerEvent = null;

    #[ORM\Column]
    #[Groups(['absence_policy:read', 'absence_policy:write'])]
    private bool $justificationRequired = false;

    /** Minimum notice period in days (e.g. 30 for paid leave, 0 for sick leave). */
    #[ORM\Column]
    #[Groups(['absence_policy:read', 'absence_policy:write'])]
    private int $noticeDays = 0;

    /** true => "jours ouvrés" (Mon-Fri), false => "jours ouvrables" (Mon-Sat). */
    #[ORM\Column]
    #[Groups(['absence_policy:read', 'absence_policy:write'])]
    private bool $countWorkingDaysOnly = true;

    #[ORM\Column]
    #[Groups(['absence_policy:read', 'absence_policy:write'])]
    private bool $active = true;

    #[Groups(['absence_policy:read'])]
    public function getLabel(): string
    {
        return $this->type->label();
    }

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

    public function getType(): AbsenceType
    {
        return $this->type;
    }

    public function setType(AbsenceType $type): static
    {
        $this->type = $type;

        return $this;
    }

    public function getDaysPerYear(): ?float
    {
        return $this->daysPerYear;
    }

    public function setDaysPerYear(?float $daysPerYear): static
    {
        $this->daysPerYear = $daysPerYear;

        return $this;
    }

    public function getDaysPerEvent(): ?float
    {
        return $this->daysPerEvent;
    }

    public function setDaysPerEvent(?float $daysPerEvent): static
    {
        $this->daysPerEvent = $daysPerEvent;

        return $this;
    }

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

    public function setJustificationRequired(bool $justificationRequired): static
    {
        $this->justificationRequired = $justificationRequired;

        return $this;
    }

    public function getNoticeDays(): int
    {
        return $this->noticeDays;
    }

    public function setNoticeDays(int $noticeDays): static
    {
        $this->noticeDays = $noticeDays;

        return $this;
    }

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

    public function setCountWorkingDaysOnly(bool $countWorkingDaysOnly): static
    {
        $this->countWorkingDaysOnly = $countWorkingDaysOnly;

        return $this;
    }

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

    public function setActive(bool $active): static
    {
        $this->active = $active;

        return $this;
    }
}
