<?php

namespace App\Models;

use App\CentralLogics\Helpers;
use App\Scopes\StoreScope;
use App\Scopes\ZoneScope;
use App\Traits\ReportFilter;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Support\Facades\Schema;

class OrderDetail extends Model
{
    use HasFactory , ReportFilter;

    protected ?array $resolvedDisplayPayloadCache = null;
    protected bool $resolvedDisplayPayloadLoaded = false;
    protected ?array $resolvedDisplayItemDetailsCache = null;
    protected bool $resolvedDisplayItemDetailsLoaded = false;
    protected static ?array $columnAvailabilityCache = null;

    protected $casts = [
        'price' => 'float',
        'discount_on_item' => 'float',
        'total_add_on_price' => 'float',
        'tax_amount' => 'float',
        'item_id'=> 'integer',
        'product_id'=> 'integer',
        'order_id'=> 'integer',
        'quantity'=>'integer',
        'qty'=>'integer',
        'item_campaign_id'=>'integer'
    ];

    protected $primaryKey   = 'id';

    public function order()
    {
        return $this->belongsTo(Order::class);
    }
    public function vendor()
    {
        return $this->order->store();
    }
    public function item()
    {
        return $this->belongsTo(Item::class, static::itemForeignKey())
            ->withoutGlobalScopes([StoreScope::class, ZoneScope::class]);
    }
    public function campaign()
    {
        return $this->belongsTo(ItemCampaign::class, 'item_campaign_id')
            ->withoutGlobalScopes([StoreScope::class, ZoneScope::class]);
    }

    protected static function boot(){
        parent::boot();
        static::addGlobalScope('order', function (Builder $builder) {
            $builder->Has('order');
        });
    }

    public function getDisplayItemDetailsAttribute(): array
    {
        if ($this->resolvedDisplayItemDetailsLoaded) {
            return $this->resolvedDisplayItemDetailsCache ?? [];
        }

        $details = data_get($this->resolveDisplayPayload(), 'item_details', []);
        $details = is_array($details) ? $details : [];

        $itemId = (int) (
            $this->item_id
            ?? $this->product_id
            ?? data_get($details, 'item_id')
            ?? data_get($details, 'product_id')
            ?? data_get($details, 'id')
            ?? 0
        );

        if (! data_get($details, 'item_id') && $itemId > 0) {
            $details['item_id'] = $itemId;
        }

        if (! data_get($details, 'product_id') && $itemId > 0) {
            $details['product_id'] = $itemId;
        }

        if (! data_get($details, 'item_campaign_id') && (int) ($this->item_campaign_id ?? 0) > 0) {
            $details['item_campaign_id'] = (int) $this->item_campaign_id;
        }

        if ($itemId > 0) {
            $item = $this->relationLoaded('item') && $this->item
                ? $this->item
                : Item::withoutGlobalScopes()->find($itemId);
            if ($item) {
                $resolvedItemName = $this->resolveRelatedModelDisplayName($item);
                if (! $this->hasMeaningfulDisplayName(data_get($details, 'name'))
                    && ! $this->hasMeaningfulDisplayName(data_get($details, 'title'))
                    && ! $this->hasMeaningfulDisplayName(data_get($details, 'item_name'))
                    && ! $this->hasMeaningfulDisplayName(data_get($details, 'product_name'))) {
                    $details['name'] = $resolvedItemName;
                    $details['title'] = $resolvedItemName;
                    $details['item_name'] = $resolvedItemName;
                    $details['product_name'] = $resolvedItemName;
                }

                if (! data_get($details, 'image_full_url') && ! empty(data_get($item, 'image_full_url'))) {
                    $details['image_full_url'] = data_get($item, 'image_full_url');
                }

                if (empty(data_get($details, 'images_full_url')) && is_array(data_get($item, 'images_full_url'))) {
                    $details['images_full_url'] = data_get($item, 'images_full_url');
                }
            }
        }

        if ((int) ($this->item_campaign_id ?? 0) > 0) {
            $campaign = $this->relationLoaded('campaign') ? $this->campaign : $this->campaign()->first();
            if ($campaign) {
                $campaignName = $this->resolveRelatedModelDisplayName($campaign);
                if (! $this->hasMeaningfulDisplayName(data_get($details, 'name'))
                    && ! $this->hasMeaningfulDisplayName(data_get($details, 'title'))
                    && ! $this->hasMeaningfulDisplayName(data_get($details, 'campaign_title'))) {
                    if ($campaignName !== '') {
                        $details['name'] = $campaignName;
                        $details['title'] = $campaignName;
                        $details['campaign_title'] = $campaignName;
                    }
                }

                if (! data_get($details, 'image_full_url') && ! empty(data_get($campaign, 'image_full_url'))) {
                    $details['image_full_url'] = data_get($campaign, 'image_full_url');
                }
            }
        }

        if (! $this->hasMeaningfulDisplayName(data_get($details, 'name'))
            && ! $this->hasMeaningfulDisplayName(data_get($details, 'title'))
            && ! $this->hasMeaningfulDisplayName(data_get($details, 'item_name'))
            && ! $this->hasMeaningfulDisplayName(data_get($details, 'product_name'))
            && ! $this->hasMeaningfulDisplayName(data_get($details, 'campaign_title'))) {
            $translatedName = $this->extractDisplayNameFromTranslations($details);
            if ($translatedName !== null) {
                $details['name'] = $translatedName;
                $details['title'] = $translatedName;
                $details['item_name'] = $translatedName;
                $details['product_name'] = $translatedName;
                if ((int) ($this->item_campaign_id ?? 0) > 0) {
                    $details['campaign_title'] = $translatedName;
                }
            }
        }

        $this->resolvedDisplayItemDetailsCache = $details;
        $this->resolvedDisplayItemDetailsLoaded = true;

        return $this->resolvedDisplayItemDetailsCache;
    }

    public function getDisplayPriceAttribute(): float
    {
        return (float) data_get($this->resolveDisplayPayload(), 'price', (float) ($this->price ?? 0));
    }

    public function getDisplayQuantityAttribute(): int
    {
        return (int) data_get(
            $this->resolveDisplayPayload(),
            'quantity',
            data_get($this->resolveDisplayPayload(), 'qty', (int) ($this->quantity ?? $this->qty ?? 0))
        );
    }

    public function getDisplayLineAmountAttribute(): float
    {
        return $this->display_price * $this->display_quantity;
    }

    public function getDisplayItemNameAttribute(): string
    {
        $details = $this->display_item_details;
        $relatedItemName = data_get($this->item, 'name');
        $relatedCampaignTitle = data_get($this->campaign, 'title');
        $relatedCampaignName = data_get($this->campaign, 'name');
        $candidates = [
            data_get($details, 'name'),
            data_get($details, 'title'),
            data_get($details, 'item_name'),
            data_get($details, 'product_name'),
            data_get($details, 'campaign_title'),
            data_get($details, 'item.name'),
            data_get($details, 'campaign.title'),
            $relatedItemName,
            $relatedCampaignTitle,
            $relatedCampaignName,
        ];

        foreach ($candidates as $candidate) {
            $name = trim((string) ($candidate ?? ''));
            if ($name !== '' && ! in_array(strtolower($name), ['item', 'campaign item'], true)) {
                return $name;
            }
        }

        return translate('messages.Item deleted!');
    }

    public function getDisplayItemImageFullUrlAttribute(): ?string
    {
        $details = $this->display_item_details;
        $relatedItemImage = data_get($this->item, 'image_full_url');
        $relatedCampaignImage = data_get($this->campaign, 'image_full_url');
        $candidates = [
            data_get($details, 'image_full_url'),
            data_get($details, 'item.image_full_url'),
            data_get($details, 'campaign.image_full_url'),
            $relatedItemImage,
            $relatedCampaignImage,
        ];

        foreach ($candidates as $candidate) {
            $image = trim((string) ($candidate ?? ''));
            if ($image !== '') {
                return $image;
            }
        }

        $image = data_get($details, 'image')
            ?? data_get($details, 'img')
            ?? data_get($details, 'item.image')
            ?? data_get($details, 'campaign.image')
            ?? data_get($details, 'images.0.img')
            ?? data_get($details, 'images.0');

        if ($image) {
            return Helpers::get_full_url('product', $image, data_get($details, 'storage', 'public'));
        }

        return null;
    }

    public function getDisplayItemReferenceIdAttribute(): ?int
    {
        $itemId = (int) (
            $this->item_id
            ?? $this->product_id
            ?? data_get($this->display_item_details, 'item_id')
            ?? data_get($this->display_item_details, 'product_id')
            ?? data_get($this->display_item_details, 'id')
            ?? 0
        );
        if ($itemId > 0) {
            return $itemId;
        }

        $campaignId = (int) ($this->item_campaign_id ?? data_get($this->display_item_details, 'item_campaign_id', 0));
        if ($campaignId > 0) {
            return $campaignId;
        }

        return null;
    }

    public static function hasColumn(string $column): bool
    {
        if (self::$columnAvailabilityCache === null) {
            self::$columnAvailabilityCache = [];
        }

        if (! array_key_exists($column, self::$columnAvailabilityCache)) {
            self::$columnAvailabilityCache[$column] = Schema::hasColumn((new static())->getTable(), $column);
        }

        return (bool) self::$columnAvailabilityCache[$column];
    }

    private static function itemForeignKey(): string
    {
        return static::hasColumn('item_id') ? 'item_id' : 'product_id';
    }

    private function hasMeaningfulDisplayName($value): bool
    {
        $name = strtolower(trim((string) ($value ?? '')));

        return $name !== '' && ! in_array($name, ['item', 'campaign item', 'item deleted!'], true);
    }

    private function extractDisplayNameFromTranslations(array $details): ?string
    {
        foreach (['translations', 'translation'] as $translationKey) {
            $translations = data_get($details, $translationKey, []);
            if (! is_array($translations)) {
                continue;
            }

            foreach ($translations as $translation) {
                if (! is_array($translation)) {
                    continue;
                }

                $translationField = strtolower(trim((string) ($translation['key'] ?? $translation['translationable_field'] ?? '')));
                $translationValue = trim((string) ($translation['value'] ?? $translation['translated_value'] ?? ''));

                if (in_array($translationField, ['name', 'title'], true) && $this->hasMeaningfulDisplayName($translationValue)) {
                    return $translationValue;
                }
            }
        }

        return null;
    }

    private function resolveRelatedModelDisplayName($model): string
    {
        foreach ([
            data_get($model, 'name'),
            data_get($model, 'title'),
            data_get($model, 'item_name'),
            data_get($model, 'product_name'),
            data_get($model, 'campaign_title'),
        ] as $candidate) {
            if ($this->hasMeaningfulDisplayName($candidate)) {
                return trim((string) $candidate);
            }
        }

        $translations = data_get($model, 'translations', data_get($model, 'translation', []));
        if (is_iterable($translations)) {
            foreach ($translations as $translation) {
                $field = strtolower(trim((string) data_get($translation, 'key', data_get($translation, 'translationable_field', ''))));
                $value = trim((string) data_get($translation, 'value', data_get($translation, 'translated_value', '')));
                if (in_array($field, ['name', 'title'], true) && $this->hasMeaningfulDisplayName($value)) {
                    return $value;
                }
            }
        }

        return '';
    }

    private function resolveDisplayPayload(): array
    {
        if ($this->resolvedDisplayPayloadLoaded) {
            return $this->resolvedDisplayPayloadCache ?? [];
        }

        $formatted = Helpers::order_details_data_formatting([$this]);
        $payload = data_get($formatted, '0', []);
        $payload = is_array($payload) ? $payload : [];

        $this->resolvedDisplayPayloadCache = $payload;
        $this->resolvedDisplayPayloadLoaded = true;

        return $this->resolvedDisplayPayloadCache;
    }
}
