<?php

namespace App\Models\Ecommerce\Product\Product\Concerns;

use App\Models\Ecommerce\Product\Property\ProductProperty;
use Illuminate\Support\Facades\Blade;

trait ProductProperties
{
    /**
     * Check if given product has given property
     */
    public function containsProperty(string $property): bool
    {
        return $this->properties->pluck('attribute.slug')->contains($property);
    }

    /**
     * Get product property
     */
    public function getProperty(string $name): ?ProductProperty
    {
        return $this->properties->first(fn ($property) => $property->attribute->slug === $name);
    }

    /**
     * Check if product has color variants
     */
    public function hasColorVariants(): bool
    {
        return $this->containsProperty('colour');
    }

    /**
     * Get product color property
     */
    public function getColorProperty(): ?ProductProperty
    {
        return $this->getProperty('colour');
    }

    /**
     * Get product color property
     */
    public function getSizeProperty(): ?ProductProperty
    {
        return $this->getProperty('size');
    }

    /**
     * Get color value of product
     */
    public function getColorValue(): ?string
    {
        $colorProperty = $this->getColorProperty();

        return $colorProperty ? $colorProperty->values->first()?->real_value : null;
    }

    /**
     * Get size value
     */
    public function getSizeValue(): ?string
    {
        $sizeProperty = $this->getSizeProperty();

        return $sizeProperty ? $sizeProperty->values->first()?->real_value : null;
    }

    /**
     * Check if product has a color.
     */
    public function hasColor(): bool
    {
        return $this->hasPropertyWithSlug('colour');
    }

    /**
     * Check if product has a size.
     */
    public function hasSize(): bool
    {
        return $this->hasPropertyWithSlug('size');
    }

    /**
     * Color property
     */
    public function getColor(): string
    {
        $product = 'productColor'.$this->id;

        if (temp_cache($product)) {
            return temp_cache($product);
        }

        cache()->put(
            key: 'productColor'.$this->id,
            value: $this->getPropertyValueBySlug('colour'),
        );

        return temp_cache($product);
    }

    /**
     * Size property
     */
    public function getSize(): string
    {
        $product = 'productSize'.$this->id;

        if (temp_cache($product)) {
            return temp_cache($product);
        }

        cache()->put(
            'productSize'.$this->id,
            $this->getPropertyValueBySlug('size'),
        );

        return temp_cache($product);
    }

    /**
     * Color variants
     */
    public function colorVariants(): array
    {
        if (temp_cache('productColorVariants')) {
            return temp_cache('productColorVariants');
        }

        $this->loadMissing(['media', 'properties', 'variations' => ['media', 'properties']]);

        $colorVariants = collect();

        // Add parent product
        $colorVariants->push([
            'slug' => $this->slug,
            'id' => $this->id,
            'image' => $this->thumbnail(),
            'color' => $this->getColor(),
        ]);

        $this->variations->each(function ($variation) use ($colorVariants) {
            $colorVariants->push([
                'slug' => $variation->slug,
                'id' => $variation->id,
                'image' => $variation->thumbnail(),
                'color' => $variation->getColor(),
            ]);
        });

        cache()->put(
            'productColorVariants',
            $colorVariants->uniqueStrict('color')->toArray(),
        );

        return $colorVariants->toArray();
    }

    /**
     * Check if a property with the given attribute slug exists
     */
    protected function hasPropertyWithSlug(string $slug): bool
    {
        if ($this->relationLoaded('properties')) {
            return $this->checkLoadedPropertiesForSlug($slug);
        }

        return $this->checkDatabaseForPropertySlug($slug);
    }

    /**
     * Check loaded properties for attribute slug
     */
    protected function checkLoadedPropertiesForSlug(string $slug): bool
    {
        foreach ($this->properties as $property) {
            if ($property->attribute->slug === $slug) {
                return true;
            }
        }

        return false;
    }

    /**
     * Check database for attribute slug
     */
    protected function checkDatabaseForPropertySlug(string $slug): bool
    {
        return $this->properties()
            ->where('attribute.slug', $slug)
            ->exists();
    }

    /**
     * Get property value by slug
     */
    public function getPropertyValueBySlug(string $slug): string
    {
        return $this->properties->firstWhere('attribute.slug', 'colour')->values->first()->real_value ?? '';
    }

    /**
     * Get size variants available for given color
     */
    public function getSizeVariantsForColor(): array
    {
        if (temp_cache('productSizeVariantsForColor')) {
            return temp_cache('productSizeVariantsForColor');
        }

        if ($this->parent_id) {
            return $this->childSizeVariantsForColor();
        }

        $this->loadMissing(['properties', 'variations', 'variations.properties']);

        $properties = $this->properties;
        $variations = $this->variations;

        $productSize = [];
        $matchingProducts = [];

        foreach ($properties as $property) {
            if ($property->attribute->slug === 'size') {
                $productSize = $property->values->first()->real_value;

                $productSize = [
                    'slug' => $this->slug,
                    'id' => $this->id,
                    'size' => $productSize,
                    'parent_id' => null,
                ];
            }

            if ($property->attribute->slug === 'colour') {
                // Color found
                $productColor = $property->values->first()->real_value;

                // Get All Sizes
                $variationAllSizes = [];

                // Iterate over to find same colors in variants
                foreach ($variations as $variation) {
                    foreach ($variation->properties as $variationProperty) {

                        if ($variationProperty->attribute->slug === 'size') {
                            $productSize = $variationProperty->values->first()->real_value;

                            $variationAllSizes[] = [
                                'slug' => $variation->slug,
                                'id' => $variation->id,
                                'parent_id' => $variation->parent_id,
                                'size' => $productSize,
                            ];
                        }

                        if ($variationProperty->attribute->slug === 'colour') {
                            // If colors match, append to array
                            $variationColor = $variationProperty->values->first()->real_value;

                            if ($productColor === $variationColor) {
                                $matchingProducts[] = [
                                    'slug' => $variation->slug,
                                    'id' => $variation->id,
                                    'color' => $productColor,
                                ];
                            }
                        }

                    }
                }

            } /* Color end */
        }

        $result = collect();
        $result->push($productSize);

        collect($variationAllSizes)->whereIn('id', collect($matchingProducts)->pluck('id'))
            ->each(function ($variationSize) use ($result) {
                $result->push($variationSize);
            });

        cache()->put(
            'productSizeVariantsForColor',
            $result->toArray(),
        );

        return $result->toArray();
    }

    public function childSizeVariantsForColor(): array
    {
        $this->loadMissing(['properties']);

        $properties = $this->properties;
        $parent = $this->parent;
        $parent->load(['properties', 'variations', 'variations.properties']);
        $variations = $parent->variations;

        $productSize = [];
        $matchingProducts = [];

        foreach ($properties as $property) {
            if ($property->attribute->slug === 'size') {
                $productSize = $property->values->first()->real_value;

                $productSize = [
                    'slug' => $this->slug,
                    'id' => $this->id,
                    'size' => $productSize,
                    'parent_id' => $this->parent_id,
                ];
            }

            if ($property->attribute->slug === 'colour') {
                // Color found
                $productColor = $property->values->first()->real_value;

                // Get All Sizes
                $variationAllSizes = [];

                // Iterate over to find same colors in variants
                foreach ($variations as $variation) {
                    if ($variation->id === $this->id) {
                        continue;
                    }

                    foreach ($variation->properties as $variationProperty) {

                        if ($variationProperty->attribute->slug === 'size') {
                            $productSize = $variationProperty->values->first()->real_value;

                            $variationAllSizes[] = [
                                'slug' => $variation->slug,
                                'id' => $variation->id,
                                'parent_id' => $variation->parent_id,
                                'size' => $productSize,
                            ];
                        }

                        if ($variationProperty->attribute->slug === 'colour') {
                            // If colors match, append to array
                            $variationColor = $variationProperty->values->first()->real_value;

                            if ($productColor === $variationColor) {
                                $matchingProducts[] = [
                                    'slug' => $variation->slug,
                                    'id' => $variation->id,
                                    'color' => $productColor,
                                ];
                            }
                        }

                    }
                }

            } /* Color end */
        }

        $result = collect();
        $result->push($productSize);

        collect($variationAllSizes)->whereIn('id', collect($matchingProducts)->pluck('id'))
            ->each(function ($variationSize) use ($result) {
                $result->push($variationSize);
            });

        return $result->toArray();
    }

    /**
     * All values of product properties
     */
    public function allValuesOfProperties(): array
    {
        return $this->properties->flatMap(function ($property) {
            return $property->values->map(function ($value) {
                return $value->real_value;
            })->filter();
        })->all();
    }

    /**
     * Name with properties
     */
    public function nameWithProperties(): string
    {
        $properties = $this->allValuesOfProperties();

        return sprintf(
            '%s %s %s',
            $this->name,
            count($properties) > 0 ? '-' : '',
            Blade::render('
                @foreach($datas as $data)
                    <strong>{{ $data }}{{ $loop->last ? "" : "," }}</strong>
                @endforeach
            ', ['datas' => $properties])
        );
    }

    public function getSizeVariants(): array
    {
        $sizeVariants = [];

        // Add parent product
        $sizeVariants[] = [
            'slug' => $this->slug,
            'id' => $this->id,
            'image' => $this->thumbnail(),
            'images_hd' => $this->getMedia('uploads')->map(fn ($media) => $media->getUrl('thumb720x720')),
            'size' => $this->getSizeValue(),
        ];

        $this->variations->each(function ($variation) use (&$sizeVariants) {
            $variationSize = $variation->getSizeValue();

            if ($variationSize && ! keyValueExistsInArray(datas: $sizeVariants, key: 'size', value: $variationSize)) {
                $sizeVariants[] = [
                    'slug' => $variation->slug,
                    'id' => $variation->id,
                    'image' => $variation->thumbnail(),
                    'images_hd' => $variation->getMedia('uploads')->map(fn ($media) => $media->getUrl('thumb720x720')),
                    'size' => $variationSize,
                ];
            }
        });

        return $sizeVariants;
    }
}
