<?php

namespace Daylight\Core\Models;

use Daylight\Core\Models\Enums\StockStatus;
use Daylight\Core\Modules\MediaLibrary\Contracts\HasMedia;
use Daylight\Core\Modules\MediaLibrary\DefaultMedia;
use Daylight\Core\Modules\MediaLibrary\Models\Concerns\InteractsWithMedia;
use Daylight\Core\Modules\Pricing\Facades\Pricing;
use Daylight\Core\Modules\Pricing\PricingManager;
use Daylight\Core\Services\Tax;
use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Support\Collection;

class Variant extends Model implements HasMedia
{
    use InteractsWithMedia;
    use SoftDeletes;

    protected $guarded = [];

    /**
     * Touch the parent product to trigger Scout re-indexing.
     */
    protected $touches = ['product'];

    protected $casts = [
        'purchasable' => 'boolean',
        'backorders' => 'boolean',
    ];

    protected $with = [
        'prices',
    ];

    public function product(): BelongsTo
    {
        return $this->belongsTo(daylightModel('product'));
    }

    public function optionValues(): BelongsToMany
    {
        return $this->belongsToMany(daylightModel('option_value'))->withTimestamps();
    }

    public function shippingClasses(): BelongsToMany
    {
        return $this->belongsToMany(daylightModel('shipping_class'));
    }

    public function taxClass(): BelongsTo
    {
        return $this->belongsTo(daylightModel('tax_class'));
    }

    public function variationName(): Attribute
    {
        $this->loadMissing([
            'optionValues.translations',
            'optionValues.option.translations',
        ]);

        return Attribute::make(
            get: function () {
                return $this->optionValues->map(function (OptionValue $optionValue) {
                    return sprintf('%s: %s',
                        $optionValue->option->name,
                        $optionValue->name
                    );
                })->reverse()->join(' / ');
            }
        );
    }

    public function isPurchasable(): bool
    {
        return $this->purchasable;
    }

    public function inStock(): bool
    {
        return $this->stock > 0;
    }

    public function hasBackorders(): bool
    {
        return $this->backorders;
    }

    public function stockStatus(): Attribute
    {
        return Attribute::make(
            get: function () {
                if ($this->inStock()) {
                    return StockStatus::IN_STOCK;
                }

                if ($this->hasBackorders()) {
                    return StockStatus::BACKORDER;
                }

                return StockStatus::OUT_OF_STOCK;
            }
        );
    }

    public function variantName(): Attribute
    {
        return Attribute::make(
            get: function () {
                return $this->optionValues->map(function (OptionValue $optionValue) {
                    return sprintf('%s: %s',
                        $optionValue->option->name,
                        $optionValue->name
                    );
                })->join(' / ');
            }
        );
    }

    public function priceIncludingVat(): Attribute
    {
        return Attribute::make(
            get: function () {
                return $this->pricing()->get()->matched?->price * (1 + Tax::defaultTaxRateForClass($this->tax_class_id) / 100);
            }
        );
    }

    public function getMedia(?string $field = null): Collection
    {
        $this->loadMissing('media.conversions');

        if ($this->media->isEmpty()) {
            return $this->product->media ?? collect();
        }

        return $this->media->where('pivot.properties.field', $field);
    }

    public function getFirstMedia(?string $field = null)
    {
        return $this->getMedia($field)->first() ?? DefaultMedia::make();
    }

    public function prices(): HasMany
    {
        return $this->hasMany(daylightModel('price'));
    }

    public function basePrices(): HasMany
    {
        return $this->prices()->whereMinQuantity(1)->whereNull('customer_group_id');
    }

    public function priceBreaks(): HasMany
    {
        return $this->prices()->where('min_quantity', '>', 1);
    }

    public function pricing(): PricingManager
    {
        return Pricing::for($this);
    }

    public function getDataLayerInformation(int $quantity = 1): array
    {
        return [
            'item_id' => $this->product->id,
            'item_name' => $this->product->name,
            'item_brand' => $this->product->brand->name,
            'item_category' => $this->product->categories->first()?->name,
            'item_variant' => $this->sku,
            'quantity' => $quantity,
            'price' => $this->pricing()->get()->matched->price / 100,
            'currency' => 'EUR',
        ];
    }
}
