<?php

namespace App\DTOs;

readonly class ScrapedListingProduct
{
    /**
     * @param  list<string>  $badges
     */
    public function __construct(
        public string $name,
        public string $url,
        public ?string $price = null,
        public ?string $listPrice = null,
        public ?string $rating = null,
        public ?string $reviewCount = null,
        public ?string $imageUrl = null,
        public array $badges = [],
    ) {}

    /**
     * @param  array<string, mixed>  $data
     */
    public static function fromArray(array $data): ?self
    {
        $name = trim((string) ($data['name'] ?? ''));
        $url = trim((string) ($data['url'] ?? ''));

        if ($name === '' || $url === '') {
            return null;
        }

        $badges = $data['badges'] ?? [];

        return new self(
            name: $name,
            url: $url,
            price: self::nullableString($data['price'] ?? null),
            listPrice: self::nullableString($data['list_price'] ?? $data['listPrice'] ?? null),
            rating: self::nullableString($data['rating'] ?? null),
            reviewCount: self::nullableString($data['review_count'] ?? $data['reviewCount'] ?? null),
            imageUrl: self::nullableString($data['image_url'] ?? $data['imageUrl'] ?? null),
            badges: is_array($badges)
                ? array_values(array_filter(array_map(
                    fn (mixed $badge): string => trim((string) $badge),
                    $badges,
                ), fn (string $badge): bool => $badge !== ''))
                : [],
        );
    }

    /**
     * @return array<string, mixed>
     */
    public function toArray(): array
    {
        return [
            'name' => $this->name,
            'url' => $this->url,
            'price' => $this->price,
            'list_price' => $this->listPrice,
            'rating' => $this->rating,
            'review_count' => $this->reviewCount,
            'image_url' => $this->imageUrl,
            'badges' => $this->badges,
        ];
    }

    private static function nullableString(mixed $value): ?string
    {
        if (! is_string($value) && ! is_numeric($value)) {
            return null;
        }

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

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