<?php


namespace App\Traits;


use App\Services\LogService;
use Illuminate\Contracts\Foundation\Application;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Cache;

trait ServiceAppAop
{

    use TestableInstant;
    /**
     * 缓存过了
     * @param array $kvPairs
     * @return Collection|null
     */
    function get(array $kvPairs):?Collection{
        return Cache::remember($this->cachingKey($kvPairs), config('cache.expirations.serviceAutoCache'), function ()use($kvPairs) {
            $query = ($this->modelClass)::query();
            foreach ($kvPairs as $column => $value){
                if (is_array($value))$query->whereIn($column,$value);
                else $query->where($column,$value);
            }
            return $query->get();
        });
    }
    function set($target,array $kvPairs){
        $update = $target->update($kvPairs);
        Cache::forget($this->cachingKey($kvPairs));
        if(isset($kvPairs['id'])){
            Cache::forget($this->cachingKey(['id'=>$kvPairs['id']]));
        }
        return $update;
    }

    protected function cachingKey(array $kvPairs): string
    {
        ksort($kvPairs);
        return $this->modelClass.md5(json_encode($kvPairs));
    }

    protected function clearCache(array $kvPairs){
        Cache::forget($this->cachingKey($kvPairs));
    }

    function create(array $kvPairs){
        $materialBox=$this->get($kvPairs);
        if($materialBox->isNotEmpty())
            return $materialBox->first();
        $this->clearCache($kvPairs);
        return ($this->modelClass)::query()->create($kvPairs);
    }

    function firstOrCreate(array $kvPairs){
        $materialBox=$this->get($kvPairs);
        if($materialBox->isNotEmpty())
            return $materialBox->first();
        $this->clearCache($kvPairs);
        return $this->create($kvPairs);
    }

    /**
     * $returnInserted 设为true返回插入的内容，是通过插入的字段返查的，所以可能会不准（看字段是否能匹配）
     * @param array $targetsArrays
     * @param bool $returnInserted 设为true返回插入的内容
     * @param bool $createdAtOn
     * @param bool $updatedAtOn
     * @return Collection|null
     */
    function insert(array $targetsArrays, $returnInserted=false, $createdAtOn=true,$updatedAtOn=true): ?Collection
    {
        if($createdAtOn||$updatedAtOn)$now = now();
        foreach ($targetsArrays as &$target){
            if($createdAtOn)$target['created_at']= $now;
            if($updatedAtOn)$target['updated_at']= $now;
        }
        ($this->modelClass)::query()->insert($targetsArrays);
        LogService::log(__METHOD__, __FUNCTION__, json_encode($targetsArrays) .
            '||' . json_encode(array_slice(debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS), 0, 4)));
        if(!$returnInserted)return null;

        return ($查回插入内容，不保证准=function ()use($targetsArrays){
            $query=($this->modelClass)::query();
            foreach ($targetsArrays as &$target){
                $query->orWhere(function($subQuery)use($target){
                    foreach ($target as $key=>$val){
                        $subQuery->where($key, $val);
                    }
                });
            }
            return $query->get();
        })();
    }
}
