<?php

namespace App\Services;

use App\Exceptions\Exception;
use App\OracleDOCOrderHeader;
use App\OracleDOCWaveDetails;
use App\Order;
use App\ValueStore;
use Carbon\Carbon;
use Illuminate\Support\Facades\Cache;
use App\Traits\ServiceAppAop;


class OracleDocWaveDetailService
{
    use ServiceAppAop;
    protected $modelClass=OracleDOCWaveDetails::class;
    public function clearCancelledOrder($orderHeaders)
    {
        if (!$orderHeaders) return;
        $orderHeader_arr = $orderHeaders->chunk(300);
        $orderHeader_arr->each(function ($items){
            $clearOrderNos = data_get($items, '*.orderno');
            $waveNos = array_values(array_diff(data_get($items, '*.waveno'),['*']));
            try {
                OracleDOCWaveDetails::query()->whereIn('OrderNo', $clearOrderNos)->whereIn('WaveNo', $waveNos)->delete();
                app('LogService')->log(__CLASS__, __FUNCTION__, 'Delete OracleDOCWaveDetails' . '  ' . json_encode($clearOrderNos).json_encode($waveNos));
            } catch (Exception $e) {
                app('LogService')->log(__CLASS__, __FUNCTION__,'Error clearCancelledOrder'.json_encode($clearOrderNos).json_encode($waveNos));
            }
        });
    }


    private function getSyncAt()
    {
        return Cache::remember('clear_cancel_order_sync_at', config('sync.clear_wave_order.cache_prefix.sync_at'), function () {
            $valueStore = ValueStore::query()->where('name', 'last_cancel_order_sync_at')->first();
            if(!$valueStore) $valueStore = ValueStore::query()->create(['name'=>'last_cancel_order_sync_at']);
            if (!$valueStore->value) return (string)Carbon::now()->subMinutes(7);
            return $valueStore->value;
        });
    }

    private function getLastSyncStartAt()
    {
        return Cache::remember('clear_cancel_order_start_at', config('sync.clear_wave_order.cache_prefix.last_start_at'), function () {
            $valueStore = ValueStore::query()->where('name', 'last_cancel_order_start_at')->first();
            if(!$valueStore) $valueStore = ValueStore::query()->create(['name'=>'last_cancel_order_start_at']);
            if ($valueStore->value) return (string)Carbon::now();
            return null;
        });
    }

    private function getLastSyncEndAt()
    {
        return Cache::remember('clear_cancel_order_start_at', config('sync.clear_wave_order.cache_prefix.last_end_at'), function () {
            $valueStore = ValueStore::query()->where('name', 'last_cancel_order_end_at')->first();
            if(!$valueStore) $valueStore = ValueStore::query()->create(['name'=>'last_cancel_order_end_at']);
            if ($valueStore->value) return (string)Carbon::now();
            return null;
        });
    }

    private function setSyncAt($time)
    {
        Cache::put(config('clear_cancel_order_sync_at'), $time);
        ValueStore::query()->where('name', 'last_cancel_order_sync_at')->update(['value'=>$time]);
    }

    private function setSyncStartAt($time)
    {
        Cache::put(config('clear_cancel_order_start_at'), $time);
        ValueStore::query()->where('name', 'last_cancel_order_start_at')->update(['value'=>$time]);
    }

    private function setSyncEndAt($time)
    {
        Cache::put(config('clear_cancel_order_start_at'), $time);
        ValueStore::query()->where('name', 'last_cancel_order_end_at')->update(['value'=>$time]);
    }

    public function clearCancelledOrderTask()
    {
        $enabled = config('sync.clear_wave_order.enabled');
        if ($enabled == false) return;
        $sync_at = $this->getSyncAt();
        $last_start_at = $this->getLastSyncStartAt();
        $last_end_at = $this->getLastSyncEndAt();
        $restart = config('clear_wave_order.cache_prefix.restart');
        $start_time = Carbon::now();

        if (isset($last_start_at) && empty($last_end_at) && $start_time->diffInMinutes(Carbon::parse($last_start_at)) < $restart) return;

        if (isset($last_start_at) && isset($last_end_at)
            && Carbon::parse($last_end_at)->lt(Carbon::parse($last_start_at))
            && $start_time->diffInMinutes(Carbon::parse($last_start_at)) < $restart)
            return;

        $orderHeaders = OracleDOCOrderHeader::query()
            ->selectRaw('orderno,waveno,edittime,erpcancelflag')
            ->where('EditTime', '>', Carbon::parse($sync_at))
            ->where('WaveNo','!=','*')
            ->where('ERPCancelFLAG', 'Y')
            ->orderByDesc('EditTime')->get();
        $orderHeaderList = $orderHeaders->chunk(50);
        $update_at = Carbon::now();
        if(count($orderHeaders)>0){
            foreach ($orderHeaderList as $items) {
                $this->clearCancelledOrder($items);
                if ($items->count() > 0) {
                    OracleDOCOrderHeader::query()
                        ->whereIn('orderno', data_get($items, '*.orderno'))
                        ->whereIn('waveno', data_get($items, '*.waveno'))
                        ->update(['waveno' => '*','editTime' =>$update_at]);
                    $json = json_encode($items->map(function ($orderHeader) {
                        return ['orderno' => $orderHeader->orderno, 'waveno' => $orderHeader->waveno];
                    }));
                    app('LogService')->log(__CLASS__, __FUNCTION__, 'update OrderHeader' . '  ' . $json);
                    $this->disposeOrderBatchId(data_get($items, '*.orderno'));
                }
            }
        }
        $end_time = (string)Carbon::now();
        $sync_at = $orderHeaders->first()->edittime ?? $sync_at;
        $this->setSyncAt($sync_at);
        $this->setSyncStartAt((string)$start_time);
        $this->setSyncEndAt($end_time);
    }


    public function disposeOrderBatchId(array $orderNos)
    {
        if(!$orderNos) return;
        try {
            $bool = Order::query()->whereIn('code', $orderNos)->update(['batch_id' => null]);
            if($bool>0) app('LogService')->log(__CLASS__, __FUNCTION__ , 'success update Order batch_id' . '  ' . json_encode($orderNos));
            else app('LogService')->log(__CLASS__, __FUNCTION__ , 'error update Order batch_id' . '  ' . json_encode($orderNos));
        } catch (\Exception $e) {
            app('LogService')->log(__CLASS__, __FUNCTION__ , 'failed update Order batch_id' . '  ' . json_encode($orderNos));
        }
    }

}
