<?php

namespace App\Services;

use App\Logistic;
use App\Owner;
use App\OwnerPriceExpress;
use App\OwnerPriceExpressProvince;
use App\Services\common\QueryService;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\DB;
use App\Traits\ServiceAppAop;


class OwnerPriceExpressService
{
    use ServiceAppAop;
    protected $modelClass=OwnerPriceExpress::class;

    public function paginate($id = null)
    {
        $query = OwnerPriceExpress::query()->with(["owners","logistics"])
            ->orderByDesc("id");
        if ($id)$query->where("id",$id);
        return $query->paginate(50);
    }

    public function find($id, $withs = [])
    {
        return OwnerPriceExpress::query()->with($withs)->find($id);
    }

    /**
     * 拷贝目标数据
     *
     * @param object|int $model
     * @param array $values
     * @param array|null $owners
     * @param array|null $logistics
     * @param array $items
     * @param bool $isLoadItem
     *
     * @return object|null
     */
    public function copy($model, $values = [], $owners = null, $logistics = null, $items = [], $isLoadItem = true)
    {
        if (is_integer($model))$model = OwnerPriceExpress::query()->find($model);
        if (!$model)return null;
        $values["operation"] = "U";
        $values["target_id"] = $model->id;
        foreach ($model->getFillable() as $column){
            if (!array_key_exists($column,$values))$values[$column] = $model[$column];
        }
        /** @var OwnerPriceExpress $copyModel */
        $copyModel = OwnerPriceExpress::query()->create($values);

        if ($owners===null){
            $query = DB::raw("SELECT * FROM owner_price_express_owner WHERE owner_price_express_id = {$model->id}");
            $owners = array_column(DB::select($query),"owner_id");
        }
        $copyModel->owners()->sync($owners);
        if ($logistics===null){
            $query = DB::raw("SELECT * FROM owner_price_express_logistic WHERE owner_price_express_id = {$model->id}");
            $logistics = array_column(DB::select($query),"logistic_id");
        }
        $copyModel->logistics()->sync($logistics);
        $insert = [];
        if ($isLoadItem){
            $model->loadMissing("details");
            /** @var \stdClass $model */
            foreach ($model->details as $item){
                $columns = ["province_id","initial_weight_price","additional_weight_price"];
                if ($items[$item->id] ?? false){
                    foreach ($columns as $column){
                        if (!array_key_exists($column,$items[$item->id]))$items[$item->id][$column] = $item[$column];
                    }
                    $obj = $items[$item->id];
                    unset($items[$item->id]);
                }else{
                    /** @var OwnerPriceExpressProvince $item */
                    $obj = $item->toArray();
                    unset($obj["id"]);
                }
                $obj["owner_price_express_id"] = $copyModel->id;
                $obj["initial_weight_price"] = json_encode($obj["initial_weight_price"]);
                $obj["additional_weight_price"] = json_encode($obj["additional_weight_price"]);
                $insert[] = $obj;
            }
        }else{
            foreach ($items as $item){
                $item["owner_price_express_id"] = $copyModel->id;
                $item["initial_weight_price"] = json_encode($item["initial_weight_price"]);
                $item["additional_weight_price"] = json_encode($item["additional_weight_price"]);
                $insert[] = $item;
            }
        }
        if ($insert)OwnerPriceExpressProvince::query()->insert($insert);
        return $copyModel;
    }

    /**
     * 审核或恢复目标集
     *
     * @param bool $isAudit
     * @param integer|null|array $ownerId
     * @param integer|null|array $ids
     */
    public function auditOrRecover($isAudit = true, $ownerId = null, $ids = null)
    {
        if (!$ownerId && !$ids)return;
        $result = app(QueryService::class)->priceModelAuditOrRecoverQuery($isAudit,OwnerPriceExpress::query(),$ownerId,$ids);
        if ($result["delete"])$this->destroy($result["delete"]);
        if ($result["update"])OwnerPriceExpress::query()->whereIn("id",$result["update"])->update(["operation"=>null,"target_id"=>null]);
        if (!is_array($ownerId))$ownerId = [$ownerId];
        foreach ($ownerId as $owner)Cache::tags("expressFeeOwner:".$owner)->flush();
    }

    public function updateDetail(array $params, array $values)
    {
        $query = OwnerPriceExpressProvince::query();
        foreach ($params as $column => $param){
            $query->where($column,$param);
        }
        return $query->update($values);
    }

    public function create(array $params)
    {
        $params["operation"] = "C";
        return OwnerPriceExpress::query()->create($params);
    }

    public function createDetail(array $params)
    {
        return OwnerPriceExpressProvince::query()->create($params);
    }

    public function isExistDetail(array $params)
    {
        $query = OwnerPriceExpressProvince::query();
        foreach ($params as $column => $param){
            $query->where($column,$param);
        }
        return $query->count();
    }

    public function destroyDetail($id)
    {
        return OwnerPriceExpressProvince::destroy($id);
    }

    public function getExistOwnerName($owner_id, $logistic_id, $id=null, $type = 'ownerPriceExpresses') :array
    {
        if (!is_array($owner_id))$owner_id = [$owner_id];
        if (!is_array($logistic_id))$logistic_id = [$logistic_id];
        $owners = Owner::query()->with([$type=>function($query)use($id){
            /** @var Builder $query */
            if ($id)$query->where("id","!=",$id);
            $query->with(["logistics"]);
        }])->whereIn("id",$owner_id)->get();
        $result = [];
        foreach ($owners as $owner){
            $arr = [];
            if ($owner->ownerPriceExpresses){
                foreach ($owner->ownerPriceExpresses as $express){
                    if ($express->logistics){
                        foreach ($express->logistics as $logistic){
                            if (array_search($logistic->id,$logistic_id) !== false)$arr[] = $logistic->name;
                        }
                    }
                }
            }
            if (count($arr)>0)$result[] = "“".$owner->name."”已绑定:".implode(",",$arr);
        }
        return $result;
    }

    public function getExistLogisticName($logistic_id, $id=null):array
    {
        $logistics = Logistic::query()->withCount(["ownerPriceExpresses"=>function($query)use($id){
            if ($id)$query->where("id","!=",$id);
        }])->whereIn("id",$logistic_id)->get();
        $arr = [];
        foreach ($logistics as $logistic){
            if ($logistic->owner_price_expresses_count > 0)$arr[] = $logistic->name;
        }
        return $arr;
    }

    public function destroy($id)
    {
        if (!$id)return 0;
        if (!is_array($id))$id = [$id];
        OwnerPriceExpressProvince::query()->whereIn("owner_price_express_id",$id)->delete();

        $query = "IN (";
        for ($i=0;$i<count($id)-1;$i++)$query .= "{$id[$i]},";
        $query .= "{$id[count($id)-1]})";

        $sql = "SELECT * FROM owner_price_express_owner WHERE owner_price_express_id {$query}";
        $owners = array_column(DB::select(DB::raw($sql)),"owner_id");
        DB::table("owner_price_express_owner")->whereIn("owner_price_express_id",$id)->delete();
        app("OwnerService")->refreshRelevance($owners,2,true);
        DB::table("owner_price_express_logistic")->whereIn("owner_price_express_id",$id)->delete();
        return OwnerPriceExpress::destroy($id);
    }

    public function update(array $params, array $values)
    {
        $query = OwnerPriceExpress::query();
        foreach ($params as $column=>$param){
            $query->where($column,$params);
        }
        return $query->update($values);
    }

    /**
     * 获取绑定承运商
     *
     * @param $owner
     * @return array
     */
    public function getBuildLogistic($owner)
    {
        return app(CacheService::class)->getOrExecute("logistics_owner_".$owner,function ()use($owner){
            $query = DB::raw(<<<sql
    SELECT logistic_id FROM `owner_price_express_owner` e
    LEFT JOIN owner_price_express_logistic l
    ON e.owner_price_express_id = l.owner_price_express_id
    WHERE e.owner_id = ?
sql
            );
            $logistics = DB::select($query,[$owner]);
            return array_column($logistics,"logistic_id");
        },null);
    }

    /**
     * @param integer $owner
     * @param integer $logistic
     * @param integer $province
     *
     * @return OwnerPriceExpress|\stdClass|null
     */
    public function getOwnerPriceExpress($owner,$logistic,$province)
    {
        return Cache::tags("expressFeeOwner:".$owner)->remember("expressFee:".$owner.$logistic.$province,config("cache.expirations.rarelyChange"),
            function ()use($owner,$logistic,$province){
                return OwnerPriceExpress::query()->with(["details"=>function($query)use($province){
                    /** @var Builder $query */
                    $query->where("province_id",$province);
                }])->whereHas("owners",function ($query)use($owner){
                    /** @var Builder $query */
                    $query->where("id",$owner);
                })->whereHas("logistics",function ($query)use($logistic){
                    /** @var Builder $query */
                    $query->where("id",$logistic);
                })->where(function(Builder $query){
                    $query->whereNull("operation")->orWhere("operation","");
                })->first();
            });
    }
    /**
     *
     * @param double $weight
     * @param integer $owner_id
     * @param integer $logistic_id
     * @param integer $province_id
     * @return array
     */
    public function matching($weight, $owner_id, $logistic_id, $province_id)
    {
        if (!$weight)return array(null,null);

        $model = $this->getOwnerPriceExpress($owner_id,$logistic_id,$province_id);
        if (!$model || count($model->details)<1)return array(null,null);

        if ($model->amount_interval){
            $total = app("OrderService")->getOrderQuantity($owner_id)+1;//获取该货主本月C端单量
            for ($i=count($model->amount_interval);$i<0;$i--){
                if ($total>=$model->amount_interval[$i]){$to1 = $i;break;}
            }
            if (isset($to1) && isset($model->weight_interval[$to1])){
                for ($i=count($model->weight_interval[$to1]);$i<0;$i--){
                    if ($weight>=$model->weight_interval[$to1][$i]){$to2 = $i;break;}
                }
            }
        }
        if (!isset($to1))$to1 = 0;
        if (!isset($to2))$to2 = 0;

        $initPrice = $model->details[0]->initial_weight_price[$to1][$to2];
        $additionalPrice = $model->details[0]->additional_weight_price[$to1][$to2];
        if ($weight <= $model->initial_weight)$money = $initPrice;
        else{
            $weight -= $model->initial_weight;
            $money = (ceil($weight/$model->additional_weight)*$additionalPrice)+$initPrice;
        }
        if ($model->tax_rate_id && $model->taxRate){
            $taxFee = $money*($model->taxRate->value/100);
        }else{
            /** @var Owner|\stdClass $owner */
            $owner = Owner::query()->with("taxRate")
                ->whereHas("taxRate")->find($owner_id);
            if ($owner)$taxFee = $money*($owner->taxRate->value/100);
            else $taxFee = null;
        }

        return array($money,$taxFee);
    }
}
