<?php

namespace App\Pricing\Entity;

use App\Appointment\Entity\Appointment;
use App\Pricing\Repository\PriceSnapshotRepository;
use App\Shared\Tenant\TenantOwnedTrait;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Uid\Uuid;

/**
 * فاکتور تفکیک‌شدهٔ **لحظهٔ ثبت** نوبت.
 *
 * قانون پنجم مستند: «تغییر قیمت هرگز نوبت‌های ثبت‌شده را عوض نمی‌کند.» امروز روی نوبت
 * فقط یک عدد (`visit_price_rials`) هست، پس بعد از تغییر تعرفه یا تخفیف نمی‌شود گفت آن
 * ۲٬۴۰۰٬۰۰۰ ریال از چه تشکیل شده بود.
 *
 * هیچ ستونی از این جدول بعد از ساخت تغییر نمی‌کند و عمداً هیچ setter ای ندارد:
 * snapshot ای که ویرایش شود دیگر snapshot نیست. اصلاح قیمت با ردیف تازه و ابطال
 * قبلی انجام می‌شود، نه با بازنویسی.
 */
#[ORM\Entity(repositoryClass: PriceSnapshotRepository::class)]
#[ORM\Table(name: 'price_snapshots')]
#[ORM\UniqueConstraint(name: 'uniq_snapshot_appointment', columns: ['appointment_id'])]
#[ORM\Index(columns: ['entity_type', 'entity_id'], name: 'idx_snapshot_tenant')]
class PriceSnapshot
{
    use TenantOwnedTrait;

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

    #[ORM\Column(type: 'string', length: 36, unique: true)]
    private string $uuid;

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

    #[ORM\Column(name: 'base_rials', type: 'bigint')]
    private int $baseRials;

    #[ORM\Column(name: 'items_rials', type: 'bigint')]
    private int $itemsRials;

    #[ORM\Column(name: 'discount_rials', type: 'bigint')]
    private int $discountRials;

    #[ORM\Column(name: 'insurance_base_rials', type: 'bigint')]
    private int $insuranceBaseRials;

    #[ORM\Column(name: 'insurance_supplementary_rials', type: 'bigint')]
    private int $insuranceSupplementaryRials;

    #[ORM\Column(name: 'tax_rials', type: 'bigint')]
    private int $taxRials;

    #[ORM\Column(name: 'final_rials', type: 'bigint')]
    private int $finalRials;

    #[ORM\Column(name: 'deposit_rials', type: 'bigint')]
    private int $depositRials;

    /** ریز تخفیف‌ها و مأخذشان — «۲۰٪ تخفیف» بدون نام، سه ماه بعد قابل توضیح نیست. */
    #[ORM\Column(type: 'json', nullable: true)]
    private ?array $breakdown = null;

    #[ORM\Column(name: 'computed_at', type: 'integer')]
    private int $computedAt;

    /** @param array<string, mixed> $breakdown */
    public function __construct(
        Appointment $appointment,
        string $entityType,
        int $entityId,
        int $baseRials,
        int $itemsRials,
        int $discountRials,
        int $insuranceBaseRials,
        int $insuranceSupplementaryRials,
        int $taxRials,
        int $finalRials,
        int $depositRials,
        array $breakdown = [],
        ?int $computedAt = null,
    ) {
        $this->uuid                        = Uuid::v4()->toRfc4122();
        $this->appointment                 = $appointment;
        $this->baseRials                   = $baseRials;
        $this->itemsRials                  = $itemsRials;
        $this->discountRials               = $discountRials;
        $this->insuranceBaseRials          = $insuranceBaseRials;
        $this->insuranceSupplementaryRials = $insuranceSupplementaryRials;
        $this->taxRials                    = $taxRials;
        $this->finalRials                  = $finalRials;
        $this->depositRials                = $depositRials;
        $this->breakdown                   = $breakdown === [] ? null : $breakdown;
        $this->computedAt                  = $computedAt ?? time();

        $this->assignTenantPair($entityType, $entityId);
    }

    public function getId(): ?int                 { return $this->id; }
    public function getUuid(): string             { return $this->uuid; }
    public function getAppointment(): Appointment { return $this->appointment; }
    public function getFinalRials(): int          { return (int) $this->finalRials; }
    public function getDepositRials(): int        { return (int) $this->depositRials; }
    public function getComputedAt(): int          { return $this->computedAt; }

    public function toArray(): array
    {
        return [
            'uuid'                          => $this->uuid,
            'appointment_uuid'              => $this->appointment->getUuid(),
            'base_rials'                    => (int) $this->baseRials,
            'items_rials'                   => (int) $this->itemsRials,
            'discount_rials'                => (int) $this->discountRials,
            'insurance_base_rials'          => (int) $this->insuranceBaseRials,
            'insurance_supplementary_rials' => (int) $this->insuranceSupplementaryRials,
            'tax_rials'                     => (int) $this->taxRials,
            'final_rials'                   => (int) $this->finalRials,
            'deposit_rials'                 => (int) $this->depositRials,
            'breakdown'                     => $this->breakdown ?? [],
            'computed_at'                   => $this->computedAt,
        ];
    }
}
