<?php

namespace App\Inventory\Entity;

use App\Inventory\Repository\InventoryItemRepository;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Uid\Uuid;

/**
 * A consumable stock item owned by a tenant (doctor/clinic). Scoped through the
 * polymorphic entity_type/entity_id pair, mirroring {@see \App\Tag\Entity\TenantTag}.
 *
 * Availability status is derived, never stored: an item with zero stock is
 * "out_of_stock", one at or below its alert threshold is "low_stock", otherwise
 * "in_stock".
 */
#[ORM\Entity(repositoryClass: InventoryItemRepository::class)]
#[ORM\Table(name: 'inventory_items')]
#[ORM\Index(columns: ['entity_type', 'entity_id'], name: 'idx_inventory_items_owner')]
class InventoryItem
{
    public const STATUS_IN_STOCK     = 'in_stock';
    public const STATUS_LOW_STOCK    = 'low_stock';
    public const STATUS_OUT_OF_STOCK = 'out_of_stock';

    public const DEFAULT_UNIT = 'عدد';

    /**
     * Allowed measurement units for a stock item. Backend is the single source of
     * truth (served via GET /api/v1/inventory-meta); the admin never hardcodes these.
     * Extend by appending — values are plain Persian strings stored as-is, so no
     * migration is needed. Most-used units are listed first for the picker.
     */
    public const UNITS = [
        'عدد', 'بسته', 'جعبه', 'قوطی', 'جفت', 'دست',
        'ویال', 'آمپول', 'قرص', 'کپسول', 'ورق (بلیستر)', 'ساشه', 'تیوب',
        'سی‌سی', 'میلی‌لیتر', 'لیتر', 'میلی‌گرم', 'گرم', 'کیلوگرم',
        'رول', 'متر', 'سانتی‌متر', 'کیسه',
    ];

    /**
     * Allowed inventory categories for a clinic/office. Same contract as {@see self::UNITS}:
     * backend-owned, plain Persian strings, extend by appending (no migration).
     */
    public const CATEGORIES = [
        'دارو',
        'لوازم مصرفی و تزریقات',
        'لوازم پانسمان و بخیه',
        'مواد ضدعفونی و استریلیزاسیون',
        'تجهیزات پزشکی',
        'بیهوشی و بی‌حسی',
        'لوازم زیبایی و پوست',
        'لوازم آزمایشگاهی',
        'لوازم دندان‌پزشکی',
        'ملزومات اداری و مصرفی دفتری',
        'سایر',
    ];

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

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

    #[ORM\Column(name: 'entity_type', type: 'string', length: 10)]
    private string $entityType;

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

    #[ORM\Column(type: 'string', length: 120)]
    private string $name;

    /** Free-text "مصرفی" note carried over from the source modal (kept for compatibility). */
    #[ORM\Column(type: 'string', length: 120, nullable: true)]
    private ?string $consumable = null;

    /** Standard category from {@see self::CATEGORIES}; primary grouping/filter dimension. */
    #[ORM\Column(type: 'string', length: 60, nullable: true)]
    private ?string $category = null;

    #[ORM\Column(type: 'string', length: 30)]
    private string $unit = self::DEFAULT_UNIT;

    /** Unit price in Rial (integer), consistent with the rest of ClinicPro. */
    #[ORM\Column(type: 'integer')]
    private int $price = 0;

    #[ORM\Column(type: 'integer')]
    private int $stock = 0;

    /** At or below this stock level the item is flagged "low". */
    #[ORM\Column(name: 'alert_threshold', type: 'integer')]
    private int $alertThreshold = 0;

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

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

    public function __construct(string $entityType, int $entityId, string $name)
    {
        $this->uuid       = Uuid::v4()->toRfc4122();
        $this->entityType = $entityType;
        $this->entityId   = $entityId;
        $this->name       = $name;
        $this->createdAt  = time();
        $this->updatedAt  = time();
    }

    public function getId(): ?int            { return $this->id; }
    public function getUuid(): string        { return $this->uuid; }
    public function getEntityType(): string  { return $this->entityType; }
    public function getEntityId(): int       { return $this->entityId; }
    public function getName(): string        { return $this->name; }
    public function getConsumable(): ?string { return $this->consumable; }
    public function getCategory(): ?string   { return $this->category; }
    public function getUnit(): string        { return $this->unit; }
    public function getPrice(): int          { return $this->price; }
    public function getStock(): int          { return $this->stock; }
    public function getAlertThreshold(): int { return $this->alertThreshold; }

    public function setName(string $v): self         { $this->name = $v; return $this->touch(); }
    public function setConsumable(?string $v): self   { $this->consumable = $v; return $this->touch(); }
    public function setCategory(?string $v): self     { $this->category = $v; return $this->touch(); }
    public function setUnit(string $v): self          { $this->unit = $v; return $this->touch(); }
    public function setPrice(int $v): self            { $this->price = max(0, $v); return $this->touch(); }
    public function setStock(int $v): self            { $this->stock = max(0, $v); return $this->touch(); }
    public function setAlertThreshold(int $v): self   { $this->alertThreshold = max(0, $v); return $this->touch(); }

    /** Derived availability — see class docblock. */
    public function getStatus(): string
    {
        if ($this->stock <= 0) {
            return self::STATUS_OUT_OF_STOCK;
        }
        if ($this->stock <= $this->alertThreshold) {
            return self::STATUS_LOW_STOCK;
        }
        return self::STATUS_IN_STOCK;
    }

    public function toArray(): array
    {
        return [
            'uuid'           => $this->uuid,
            'name'           => $this->name,
            'consumable'     => $this->consumable,
            'category'       => $this->category,
            'unit'           => $this->unit,
            'price'          => $this->price,
            'stock'          => $this->stock,
            'alertThreshold' => $this->alertThreshold,
            'status'         => $this->getStatus(),
        ];
    }

    private function touch(): self
    {
        $this->updatedAt = time();
        return $this;
    }
}
