<?php

namespace App\Models;

use App\CentralLogics\Helpers;
use App\Models\Vendor;
use App\Scopes\ZoneScope;
use Brian2694\Toastr\Facades\Toastr;
use Illuminate\Support\Str;
use Illuminate\Database\Eloquent\Model;

class Store extends Model
{

    protected $casts = [
        'minimum_order' => 'float',
        'comission' => 'float',
        'tax' => 'float',
        'minimum_shipping_charge' => 'float',
        'per_km_shipping_charge' => 'float',
        'schedule_order'=>'boolean',
        'free_delivery'=>'boolean',
        'vendor_id'=>'integer',
        'status'=>'integer',
        'delivery'=>'boolean',
        'take_away'=>'boolean',
        'zone_id'=>'integer',
        'module_id'=>'integer',
        'item_section'=>'boolean',
        'reviews_section'=>'boolean',
        'active'=>'boolean',
        'gst_status'=>'boolean',
        'pos_system'=>'boolean',
        'self_delivery_system'=>'integer',
        'open'=>'integer',
        'gst_code'=>'string',
        'off_day'=>'string',
        'gst'=>'string',
        'veg'=>'integer',
        'non_veg'=>'integer',
        'order_place_to_schedule_interval'=>'integer',
        'featured'=>'integer',
        'prescription_order'=>'boolean',
        'category_ids' => 'array',
    ];

    protected $appends = ['gst_status','gst_code'];

    /**
     * The attributes that should be hidden for arrays.
     *
     * @var array
     */
    protected $hidden = [
        'gst'
    ];

    public function vendor()
    {
        return $this->belongsTo(Vendor::class);
    }

    public function module()
    {
        return $this->belongsTo(Module::class);
    }

    public function items()
    {
        return $this->hasMany(Item::class);
    }

    public function schedules()
    {
        return $this->hasMany(StoreSchedule::class)->orderBy('day', 'ASC');
    }

    public function deliverymen()
    {
        return $this->hasMany(DeliveryMan::class);
    }

    public function orders()
    {
        return $this->hasMany(Order::class);
    }

    public function discount()
    {
        return $this->hasOne(Discount::class);
    }

    public function zone()
    {
        return $this->belongsTo(Zone::class);
    }

    public function campaigns()
    {
        return $this->belongsToMany(Campaign::class);
    }

    public function itemCampaigns()
    {
        return $this->hasMany(ItemCampaign::class);
    }

    public function reviews()
    {
        return $this->hasManyThrough(Review::class, Item::class);
    }

    public function getScheduleOrderAttribute($value)
    {
        return (boolean)(\App\CentralLogics\Helpers::schedule_order()?$value:0);
    }
    public function getRatingAttribute($value)
    {
        $ratings = json_decode($value, true);
        $rating5 = isset($ratings[5]) ? $ratings[5] : 0;
        $rating4 = isset($ratings[4]) ? $ratings[4] : 0;
        $rating3 = isset($ratings[3]) ? $ratings[3] : 0;
        $rating2 = isset($ratings[2]) ? $ratings[2] : 0;
        $rating1 = isset($ratings[1]) ? $ratings[1] : 0;
        return [$rating5, $rating4, $rating3, $rating2, $rating1];
    }

    public function getGstStatusAttribute()
    {
        $gst = json_decode($this->gst, true);
        if (json_last_error() !== JSON_ERROR_NONE || !is_array($gst)) {
            // handle JSON decoding error or invalid data
            return false; // or throw an exception, log an error, etc.
        }
        return isset($gst['status']) ? (bool)$gst['status'] : false;
    }

    public function getGstCodeAttribute()
    {
        $gst = json_decode($this->gst, true);
        if (json_last_error() !== JSON_ERROR_NONE || !is_array($gst)) {
            // handle JSON decoding error or invalid data
            return ''; // or throw an exception, log an error, etc.
        }
        return isset($gst['code']) ? (string)$gst['code'] : '';
    }

    public function scopeModule($query, $module_id)
    {
        return $query->where('module_id', $module_id);
    }

    public function scopeDelivery($query)
    {
        $query->where('delivery',1);
    }

    public function scopeTakeaway($query)
    {
        $query->where('take_away',1);
    }

    public function scopeActive($query)
    {
        return $query->where('status', 1);
    }

    public function scopeFeatured($query)
    {
        return $query->where('featured', '=', 1);
    }

    public function scopeOpened($query)
    {
        return $query->where('active', 1);
    }


    public function scopeWithOpen($query,$longitude,$latitude)
    {
        $query->selectRaw('*, IF(((select count(*) from `store_schedule` where `stores`.`id` = `store_schedule`.`store_id` and `store_schedule`.`day` = '.now()->dayOfWeek.' and `store_schedule`.`opening_time` < "'.now()->format('H:i:s').'" and `store_schedule`.`closing_time` >"'.now()->format('H:i:s').'") > 0), true, false) as open,ST_Distance_Sphere(point(longitude, latitude),point('.$longitude.', '.$latitude.')) as distance');
    }

    public function scopeWeekday($query)
    {
        return $query->where('off_day', 'not like', "%".now()->dayOfWeek."%");
    }

    protected static function booted()
    {
        static::addGlobalScope(new ZoneScope);
    }

    public function scopeType($query, $type)
    {
        if($type == 'veg')
        {
            return $query->where('veg', true);
        }
        else if($type == 'non_veg')
        {
            return $query->where('non_veg', true);
        }

        return $query;

    }

    protected static function boot()
    {
        parent::boot();
        static::created(function ($store) {
            $store->slug = $store->generateSlug($store->name);
            $store->save();
        });
    }

    private function generateSlug($name)
    {
        $slug = Str::slug($name);
        if ($max_slug = static::where('slug', 'like',"{$slug}%")->latest('id')->value('slug')) {

            if($max_slug == $slug) return "{$slug}-2";

            $max_slug = explode('-',$max_slug);
            $count = array_pop($max_slug);
            if (isset($count) && is_numeric($count)) {
                $max_slug[]= ++$count;
                return implode('-', $max_slug);
            }
        }
        return $slug;
    }

    public static function getCountOfOrder($storeID, $fromDate = '', $toDate = '', $orderStatus = '')
    {
        $orders = new Order;
        $orders = $orders->where('store_id', $storeID);
        if(!empty($fromDate)){
            $orders = $orders->where('created_at', '>=', $fromDate . ' 00:00:00');
        }
        if(!empty($toDate)){
            $orders = $orders->where('created_at', '<=', $toDate . ' 23:59:59');
        }
        if(!empty($orderStatus)){
            $orders = $orders->where('order_status', $orderStatus);
        }
        return $orders->count();
    }

    public function orderTransactions ($fromDate = '', $toDate = '')
    {
        $result = $this->hasMany(OrderTransaction::class);
        if(!empty($fromDate) and !empty($toDate)){
            $result = $result->where('created_at', '>=', $fromDate)->where('created_at', '<=', $toDate);
        }
        return $result;
    }

    public static function getStoreTotalEarning ($store, $fromDate = '', $toDate = '')
    {
        return $store->orderTransactions($fromDate, $toDate)->sum('store_amount');
    }

    public function getStoreAdminCommission ($store, $fromDate = '', $toDate = '')
    {
        return $store->orderTransactions('', '')->sum('order_amount') - $store->orderTransactions('', '')->sum('store_amount') - $store->orderTransactions('', '')->sum('delivery_charge');
    }

    public static function getTotalCollectedFromStore($store, $fromDate = '', $toDate = '')
    {
        $result = AccountTransaction::where('from_type', 'store')->where('from_id', $store->id);
        if(!empty($fromDate) and !empty($toDate)){
            $result = $result->where('created_at', '>=', $fromDate)->where('created_at', '<=', $toDate);
        }
        return $result->sum('amount');
    }

    public static function getStoreTheRemainingBalance($store, $fromDate = '', $toDate = '')
    {
        return Store::getStoreAdminCommission ($store, '', '') - Store::getTotalCollectedFromStore($store, '', '');
    }

    public static function acceptOrderFromStore($order, $sendNotification = true): array
    {
        $result = [
            'errors' => '',
            'result' => '',
        ];
        $order->order_status = 'confirmed';
        $order['confirmed'] = now();

        if($sendNotification) {
            $customerNotificationTitle = $order->customer->current_language_key == 'en' ? 'Your order has been confirmed by the store, your order will be prepared.' : 'تم تأكيد طلبك من المتجر، سيتم تحضير طلبك.';
            $conversationId = Message::where('order_id', $order->id)->first()->conversation_id;
            $data = [
                'title' => $customerNotificationTitle,
                'description' => '',
                'order_id' => $order->id,
                'image' => '',
                'message' => json_encode($customerNotificationTitle),
                'type' => 'message',
                'conversation_id' => $conversationId,
                'sender_type' => 'delivery_man'
            ];
            if (!Helpers::sendOrderNotificationToCustomer($order, $customerNotificationTitle, '', $data)) {
                $result['errors'] = 'push_notification_to_customer_failed';
            }
            if (!Helpers::sendOrderNotificationToDeliveryMan($order, 'تم قبول الطلب من المطعم', 'الرجاء التوجه إلى المطعم.')) {
                $result['errors'] = 'push_notification_to_delivery_man_failed';
            }
        }

        $order->save();
        if(empty($result['errors'])) {
            $result['result'] = 'order_confirmed_successfully';
        }
        return $result;
    }

    public static function rejectOrderFromStore($order, $reason)
    {
        $result = [
            'errors' => '',
            'result' => '',
        ];
        if($order->delivery_man)
        {
            $dm = $order->delivery_man;
            $dm->current_orders = $dm->current_orders > 1 ? $dm->current_orders - 1 : 0;
            $dm->save();
        }
        $order->order_status = 'canceled';
        $order['canceled'] = now();
        $order->cancellation_reason = $reason;
        $order->canceled_by = 'store';

        $customerNotificationTitle = $order->customer->current_language_key == 'en' ? 'Your order rejected by store!' : 'تم رفض طلبك من المتجر!';
        if(!Helpers::sendOrderNotificationToCustomer($order, $customerNotificationTitle, $reason))
        {
            $result['errors'] = 'push_notification_to_customer_failed';
        }

        $data = [
            'title' => 'تم رفض الطلب من المتجر' . ' (#'. $order->id .')',
            'description' => $order->cancellation_reason,
            'order_id' => $order->id,
            'image' => '',
            'type' => 'order_status'
        ];
        if(!Helpers::sendOrderNotificationToDeliveryMan($order, 'تم رفض الطلب من المتجر!', $reason, $data))
        {
            $result['errors'] = 'push_notification_to_delivery_man_failed';
        }

        $order->save();
        if(empty($result['errors'])) {
            $result['result'] = 'order_canceled_successfully';
        }
        return $result;
    }

}
