<?php

namespace App\Branch\Entity;

use App\Branch\Repository\BranchWorkingHoursRepository;
use App\Doctor\Entity\DoctorAddress;
use App\Shared\Tenant\TenantOwnedTrait;
use Doctrine\ORM\Mapping as ORM;

/**
 * ساعت کاری هفتگی یک شعبه — و «شعبه» همان {@see DoctorAddress} است، نه جدولی جدا
 * ({@see docs/new_feture/taskes/_shared/branch-is-doctor-address.md}).
 *
 * uuid ندارد (از request قابل ارجاع نیست) ولی جفت محیط دارد. اول به‌عنوان فرزند
 * aggregate با ریشهٔ DoctorAddress ثبت شد و TenantSchemaCoverageTest درست ردش کرد:
 * ریشه‌اش خودش در GlobalTables::ENTITIES سراسری است، پس آن مسیر هیچ تضمینی نمی‌داد.
 * جفت گرفتن ممکن است چون type آدرس نگاشتی کامل به محیط دارد — personal ⇒ (doctor,
 * doctorId) و clinic ⇒ (clinic, clinicId) — و آدرس هم فقط در همان محیط فهرست می‌شود،
 * پس هیچ ردیفی بی‌دلیل پنهان نمی‌شود. نتیجه: TenantFilter واقعاً پوششش می‌دهد و
 * {@see \App\Branch\Service\BranchResolver} لایهٔ دوم است نه تنها لایه.
 *
 * زمان‌ها «دقیقه از نیمه‌شب» است نه رشتهٔ "09:00": تقاطع دو بازه محاسبهٔ عددی است و
 * مقایسهٔ رشته‌ای در «9:00» < «10:00» غلط جواب می‌دهد.
 */
#[ORM\Entity(repositoryClass: BranchWorkingHoursRepository::class)]
#[ORM\Table(name: 'branch_working_hours')]
#[ORM\UniqueConstraint(name: 'uniq_bwh_address_day_seq', columns: ['address_id', 'day_of_week', 'sequence'])]
#[ORM\Index(columns: ['address_id', 'day_of_week', 'active'], name: 'idx_bwh_address_day')]
#[ORM\Index(columns: ['entity_type', 'entity_id'], name: 'idx_bwh_tenant')]
class BranchWorkingHours
{
    use TenantOwnedTrait;

    public const MINUTES_IN_DAY = 1440;

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

    #[ORM\ManyToOne(targetEntity: DoctorAddress::class)]
    #[ORM\JoinColumn(name: 'address_id', referencedColumnName: 'id', nullable: false, onDelete: 'CASCADE')]
    private DoctorAddress $address;

    /** ۰=شنبه … ۶=جمعه — همان قرارداد SlotCalculatorService */
    #[ORM\Column(name: 'day_of_week', type: 'smallint')]
    private int $dayOfWeek;

    /** بازهٔ چندم آن روز؛ سرور تخصیصش می‌دهد، نه کلاینت */
    #[ORM\Column(type: 'smallint', options: ['default' => 0])]
    private int $sequence = 0;

    #[ORM\Column(name: 'start_minute', type: 'smallint')]
    private int $startMinute;

    #[ORM\Column(name: 'end_minute', type: 'smallint')]
    private int $endMinute;

    #[ORM\Column(type: 'boolean', options: ['default' => true])]
    private bool $active = true;

    public function __construct(
        DoctorAddress $address,
        int $dayOfWeek,
        int $startMinute,
        int $endMinute,
        int $sequence = 0,
    ) {
        $this->address     = $address;
        $this->dayOfWeek   = $dayOfWeek;
        $this->startMinute = $startMinute;
        $this->endMinute   = $endMinute;
        $this->sequence    = $sequence;

        $this->assignTenantPair($address->tenantEntityType(), $address->tenantEntityId());
    }

    public function getId(): ?int               { return $this->id; }
    public function getAddress(): DoctorAddress { return $this->address; }
    public function getDayOfWeek(): int         { return $this->dayOfWeek; }
    public function getSequence(): int          { return $this->sequence; }
    public function getStartMinute(): int       { return $this->startMinute; }
    public function getEndMinute(): int         { return $this->endMinute; }
    public function isActive(): bool            { return $this->active; }

    public function setActive(bool $v): self { $this->active = $v; return $this; }

    public function toArray(): array
    {
        return [
            'sequence'     => $this->sequence,
            'start_minute' => $this->startMinute,
            'end_minute'   => $this->endMinute,
            'start_time'   => self::formatMinute($this->startMinute),
            'end_time'     => self::formatMinute($this->endMinute),
            'active'       => $this->active,
        ];
    }

    /** ۱۴۴۰ به «۲۴:۰۰» تبدیل می‌شود، نه «۰۰:۰۰» — پایانِ روز است نه آغازش. */
    public static function formatMinute(int $minute): string
    {
        return sprintf('%02d:%02d', intdiv($minute, 60), $minute % 60);
    }
}
