<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
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\Relations\HasOne;
use Illuminate\Support\Facades\Cache;
use Morilog\Jalali\Jalalian;

class Store extends Model
{
    use HasFactory;

    /**
     * The attributes that are mass assignable.
     *
     * @var array<int, string>
     */
    protected $fillable = [
        'user_id',

        'uuid',
        'name',
        'bio',
        'logo',

        'meta',

        'information',

        'view_count',
        'type',
        'direct_post',
        'reason',
        'status',
    ];

    protected $casts = [
        'user_id' => 'integer',
        'view_count' => 'integer',
        'direct_post' => 'boolean',
    ];

    /**
     * additional data
     */
    protected $appends = [
        'get_logo',
        'get_meta',
        'get_information',
        'get_formatted_view_count',
        'products_count',
        'consignments_count',
        'transportation_status',
        'jalali_created_at',
        'jalali_updated_at',

        'safe',
    ];

    public function getGetLogoAttribute()
    {
        $logo = asset('img/temp/store-logo.png');
        if ($this->logo != null) {
            $file = Cache::remember('files_' . $this->logo, now()->addMonth(), function () {
                return File::find($this->logo);
            });
            if ($file != null && $file->type == "image") {
                $logo = asset($file->url);
            }
        }
        return $logo;
    }

    public function getGetMetaAttribute()
    {
        return Cache::remember('store_get_meta_' . $this->id, now()->addMonth(), function () {
            // get orders count
            $cancelledItems = $this->consignmentItems()->where('status', 'cancelled')->count();
            $returnedItems = $this->consignmentItems()->where('status', 'returned')->count();
            $sentItems = $this->consignmentItems()->where(function ($query) {
                $query->where('status', 'sent')->orWhere('status', 'delivered');
            })->count();

            // get store commitment to send
            $commitmentToSend = null;
            if ($sentItems > $cancelledItems) {
                $commitmentToSend = round(100 - ($cancelledItems * 100 / $sentItems));
            } else if ($sentItems < $cancelledItems) {
                $commitmentToSend = round($sentItems * 100 / $cancelledItems);
            }

            // get store returned percent
            $returnedPercent = null;
            if ($sentItems > $returnedItems) {
                $returnedPercent = round(100 - ($returnedItems * 100 / $sentItems));
            } else if ($sentItems < $returnedItems) {
                $returnedPercent = round($sentItems * 100 / $returnedItems);
            }

            // Buyer satisfaction
            $productSatisfaction = 0;
            $commentsCount = 0;
            /*$products = $this->products()->where('status', '!=', 'deleted')->where('status', '!=', 'deep_deleted');
            foreach ($products->get() as $product) {
                $productCommentCount = (int)str_replace(',', '', $product->comments_info['count']);
                if ($productCommentCount > 0) {
                    $productSatisfaction += $product->comments_info['rating_percent'] / $products->count();
                    $commentsCount += $productCommentCount;
                }
            }*/
            $productSatisfaction = $productSatisfaction > 0 ? $productSatisfaction : null;

            // store performance
            $performance = '-';
            $performanceCount = 0;
            if ($commitmentToSend != null) {
                $performanceCount += 1;
            }
            if ($returnedPercent != null) {
                $performanceCount += 1;
            }
            if ($productSatisfaction != null) {
                $performanceCount += 1;
            }

            if ($performanceCount > 0) {
                $performancePercent = (($commitmentToSend != null ? $commitmentToSend : 0) + ($returnedPercent != null ? $returnedPercent : 0) + ($productSatisfaction != null ? $productSatisfaction : 0)) / $performanceCount;
            } else {
                $performancePercent = 100;
            }

            if ($performancePercent >= 90) {
                $performance = 'best';
            } else if ($performancePercent >= 70) {
                $performance = 'good';
            } else if ($performancePercent >= 50) {
                $performance = 'average';
            } else if ($performancePercent >= 30) {
                $performance = 'weak';
            } else {
                $performance = 'awful';
            }

            return [
                'commitment_to_send' => $commitmentToSend,
                'returned_percent' => $returnedPercent,
                'product_satisfaction' => $productSatisfaction,
                'comments_count' => $commentsCount,
                'performance' => $performance,
            ];
        });
    }

    public function getGetInformationAttribute()
    {
        $information = $this->information != null ? unserialize($this->information) : [];

        if (array_key_exists('company_type', $information)) {
            $information['company_type_id'] = $information['company_type'];
            $information['company_type'] = __('messages.word.' . $information['company_type']);
        }

        // genuine identity
        $information['national_card_image_url'] = null;
        if (array_key_exists('national_card_image', $information)) {
            if (File::find($information['national_card_image']) != null) {
                $information['national_card_image_url'] = route('private_media', $information['national_card_image']);
            }
        }

        // legal identity
        $information['legal_identity_image_url'] = null;
        if (array_key_exists('legal_identity_image', $information)) {
            if (File::find($information['legal_identity_image']) != null) {
                $information['legal_identity_image_url'] = route('private_media', $information['legal_identity_image']);
            }
        }

        if (!isset($information['map']) || $information['map'] == null) {
            $information['map'] = ["longitude" => 54.36281969540723, "latitude" => 32.69672648316882, "zoom" => 5.2];
        }

        return $information;
    }

    public function getGetFormattedViewCountAttribute()
    {
        return number_format($this->view_count);
    }

    public function getProductsCountAttribute()
    {
        return $this->products()->count();
    }

    public function getConsignmentsCountAttribute()
    {
        return Cache::remember('store_consignments_count_' . $this->id, now()->addMonth(), function () {
            return [
                'sent' => $this->consignments()->where(function ($query) {
                    $query->where('status', 'sent_to_main_storage')->orWhere('status', 'delivered_to_main_storage')->orWhere('status', 'sent_to_customer')->orWhere('status', 'delivered');
                })->count(),
                'cancelled' => $this->consignments()->where('status', 'cancelled')->count(),
                'awaiting' => $this->consignments()->where('status', 'awaiting_seller')->count(),
            ];
        });
    }

    public function getTransportationStatusAttribute()
    {
        $paymentMeta = PaymentMeta::where('store_id', $this->id)->first();
        if ($paymentMeta != null && $paymentMeta->post_ways != null &&  count(unserialize($paymentMeta->post_ways)) > 0) {
            $postWays = unserialize($paymentMeta->post_ways);
            $hasActive = collect($postWays)->contains(function ($item) {
                return $item['status'] === true;
            });
            return $hasActive;
        }

        return false;
    }

    public function getJalaliCreatedAtAttribute()
    {
        $date = [
            Jalalian::forge($this->created_at)->format('%d %B %Y'),
            Jalalian::forge($this->created_at)->format('Y/m/d'),
            Jalalian::forge($this->created_at)->format('H:i - Y/m/d'),
            Jalalian::forge($this->created_at)->ago(),
            Jalalian::forge($this->created_at)->getTimestamp(),
        ];
        return $date;
    }

    public function getJalaliUpdatedAtAttribute()
    {
        $date = [
            Jalalian::forge($this->updated_at)->format('%d %B %Y'),
            Jalalian::forge($this->updated_at)->format('Y/m/d'),
            Jalalian::forge($this->updated_at)->format('H:i - Y/m/d'),
            Jalalian::forge($this->updated_at)->ago(),
            Jalalian::forge($this->updated_at)->getTimestamp(),
        ];
        return $date;
    }

    public function getSafeAttribute()
    {
        return [
            'id' => $this->id,
            'uuid' => $this->uuid,
            'name' => $this->name,
            'bio' => $this->bio,
            'get_logo' => $this->get_logo,
            'get_meta' => $this->get_meta,
            'direct_post' => $this->direct_post,
            'jalali_created_at' => $this->jalali_created_at,
        ];
    }
    /** end append */

    /**
     * Get the route key for the model.
     *
     * @return string
     */
    public function getRouteKeyName()
    {
        return 'uuid';
    }

    /**
     * remove cache data in update
     */
    protected static function boot()
    {
        parent::boot();

        static::saved(function ($store) {
            if (array_key_exists('view_count', $store->getDirty())) return;

            Cache::forget('article_user_' . $store->user_id);
            Cache::forget('comment_user_' . $store->user_id);
        });

        static::deleted(function ($store) {
            Cache::forget('article_user_' . $store->user_id);
            Cache::forget('comment_user_' . $store->user_id);
        });
    }

    /* relationships **************/
    public function user(): BelongsTo
    {
        return $this->belongsTo(User::class);
    }

    public function products(): BelongsToMany
    {
        return $this->belongsToMany(Product::class)->withPivot('created_at');
    }

    public function inventories(): HasMany
    {
        return $this->hasMany(Inventory::class);
    }

    public function storages(): HasMany
    {
        return $this->hasMany(Storage::class);
    }

    public function paymentMeta(): HasOne
    {
        return $this->hasOne(PaymentMeta::class);
    }

    public function consignments(): HasMany
    {
        return $this->hasMany(Consignment::class);
    }

    public function consignmentItems(): HasMany
    {
        return $this->hasMany(ConsignmentItem::class);
    }
}
