<?php
/**
 * BookiFlex Cart Extension
 *
 * @package    BookiFlex
 * @subpackage Cart
 * @author     BookiFlex
 * @copyright  Copyright (c) 2025 BookiFlex
 * @license    GPL-2.0-or-later
 *
 * @link       https://bookiflex.com
 */


declare(strict_types=1);
namespace BookiFlex\Extensions\Cart\Model;

use BookiFlex\Extensions\Cart\Contract\CartItemInterface;
use BookiFlex\Core\Model\Identifiable;
use BookiFlex\Core\Model\Timestamps;


defined( 'ABSPATH' ) || exit;

class CartItem
{
    use Identifiable;
    use Timestamps;

    private Cart $cart;
    private string $type;
    private string $hash;
    private int $quantity;
    private ?int $unitPrice = null;
    private array $summary = [];
    private array $data;
    private ?int $sortOrder = null;

    private function __construct(
        Cart $cart,
        string $type,
        string $hash,
        int $quantity,
        array $data
    ) {
        $this->cart = $cart;
        $this->type = $type;
        $this->hash = $hash;
        $this->quantity = $quantity;
        $this->data = $data;
        $this->createdAt = new \DateTimeImmutable();
    }

    /**
     * Create from domain item
     */
    public static function create(Cart $cart, CartItemInterface $item, int $quantity = 1): self
    {
        $cartItem = new self(
            $cart,
            $item->getType(),
            $item->getHash(),
            $quantity,
            $item->toArray()
        );

        $cartItem->unitPrice = $item->calculateUnitPrice();
        $cartItem->summary = [];

        return $cartItem;
    }

    /**
     * Convert back to domain object
     */
    public function toDomainObject(): CartItemInterface
    {
        $className = $this->getItemClass();

        if (!class_exists($className)) {
            throw new \RuntimeException(
                sprintf(
                    'Unknown cart item type: %s',
                    $this->type
                )
            );
        }

        return $className::fromArray($this->data);
    }

    /**
     * Get item class by type
     */
    private function getItemClass(): string
    {
        return match($this->type) {
            AccommodationCartItem::TYPE => AccommodationCartItem::class,
            ExtraCartItem::TYPE => ExtraCartItem::class,
            default => throw new \InvalidArgumentException(
                sprintf(
                    'Unknown item type: %s',
                    $this->type
                )
            )
        };
    }

    // Getters and setters

    public function getCart(): Cart
    {
        return $this->cart;
    }

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

    public function getHash(): string
    {
        return $this->hash;
    }

    public function getQuantity(): int
    {
        return $this->quantity;
    }

    public function setQuantity(int $quantity): void
    {
        $this->quantity = max(0, $quantity);
        $this->updatedAt = new \DateTimeImmutable();
    }

    public function getTotalPrice(): int
    {
        return ($this->unitPrice ?? 0) * $this->quantity;
    }

    public function getUnitPrice(): ?int
    {
        return $this->unitPrice;
    }

    public function setUnitPrice(?int $unitPrice): void
    {
        $this->unitPrice = $unitPrice;
        $this->updatedAt = new \DateTimeImmutable();
    }

    public function getData(): array
    {
        return $this->data;
    }

    public function setData(array $data): void
    {
        $this->data = $data;
        $this->updatedAt = new \DateTimeImmutable();
    }

    public function getSortOrder(): ?int
    {
        return $this->sortOrder;
    }

    public function setSortOrder(?int $sortOrder): void
    {
        $this->sortOrder = $sortOrder;
    }

    public function getSummary(): array
    {
        return $this->summary;
    }
}
