<?php

namespace App\DTOs;

readonly class CatalogProduct
{
    /**
     * @param  list<string>  $chips
     * @param  list<string>  $pros
     * @param  list<string>  $cons
     */
    public function __construct(
        public string $name,
        public string $brand,
        public string $bestFor,
        public string $price,
        public ?string $listPrice,
        public ?string $discount,
        public string $rating,
        public string $reviewCount,
        public ?string $priceHistory,
        public string $imageUrl,
        public string $retailerUrl,
        public array $chips,
        public ?string $convertibility,
        public ?string $certification,
        public string $summary,
        public string $summaryShort,
        public string $whyItStandsOut,
        public string $whyShort,
        public array $pros,
        public array $cons,
        public string $tradeoffNote,
        public string $sourcesNote,
    ) {}

    /**
     * @param  array<string, mixed>  $data
     */
    public static function fromArray(array $data, string $retailerUrl = '', string $imageUrl = ''): self
    {
        return new self(
            name: (string) ($data['name'] ?? ''),
            brand: (string) ($data['brand'] ?? ''),
            bestFor: (string) ($data['best_for'] ?? ''),
            price: (string) ($data['price'] ?? ''),
            listPrice: self::nullableString($data['list_price'] ?? null),
            discount: self::nullableString($data['discount'] ?? null),
            rating: (string) ($data['rating'] ?? ''),
            reviewCount: (string) ($data['review_count'] ?? ''),
            priceHistory: self::nullableString($data['price_history'] ?? null),
            imageUrl: $imageUrl !== '' ? $imageUrl : (string) ($data['image_url'] ?? ''),
            retailerUrl: $retailerUrl !== '' ? $retailerUrl : (string) ($data['retailer_url'] ?? ''),
            chips: self::stringList($data['chips'] ?? []),
            convertibility: self::nullableString($data['convertibility'] ?? null),
            certification: self::nullableString($data['certification'] ?? null),
            summary: (string) ($data['summary'] ?? ''),
            summaryShort: (string) ($data['summary_short'] ?? ''),
            whyItStandsOut: (string) ($data['why_it_stands_out'] ?? ''),
            whyShort: (string) ($data['why_short'] ?? ''),
            pros: self::stringList($data['pros'] ?? []),
            cons: self::stringList($data['cons'] ?? []),
            tradeoffNote: (string) ($data['tradeoff_note'] ?? ''),
            sourcesNote: (string) ($data['sources_note'] ?? ''),
        );
    }

    /**
     * @return array<string, mixed>
     */
    public function toArray(): array
    {
        return [
            'name' => $this->name,
            'brand' => $this->brand,
            'best_for' => $this->bestFor,
            'price' => $this->price,
            'list_price' => $this->listPrice,
            'discount' => $this->discount,
            'rating' => $this->rating,
            'review_count' => $this->reviewCount,
            'price_history' => $this->priceHistory,
            'image_url' => $this->imageUrl,
            'retailer_url' => $this->retailerUrl,
            'chips' => $this->chips,
            'convertibility' => $this->convertibility,
            'certification' => $this->certification,
            'summary' => $this->summary,
            'summary_short' => $this->summaryShort,
            'why_it_stands_out' => $this->whyItStandsOut,
            'why_short' => $this->whyShort,
            'pros' => $this->pros,
            'cons' => $this->cons,
            'tradeoff_note' => $this->tradeoffNote,
            'sources_note' => $this->sourcesNote,
        ];
    }

    private static function nullableString(mixed $value): ?string
    {
        if ($value === null) {
            return null;
        }

        $value = trim((string) $value);

        return $value === '' ? null : $value;
    }

    /**
     * @return list<string>
     */
    private static function stringList(mixed $value): array
    {
        if (! is_array($value)) {
            return [];
        }

        return array_values(array_map(strval(...), $value));
    }
}
