<?php

namespace App\Services;

use App\Owner;
use App\OwnerPriceLogistic;
use App\OwnerPriceLogisticDetail;
use App\Services\common\QueryService;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Facades\DB;
use App\Traits\ServiceAppAop;

class OwnerPriceLogisticService
{
    use ServiceAppAop;
    protected $modelClass=OwnerPriceLogistic::class;
    public function paginate($id = null)
    {
        $query = OwnerPriceLogistic::query()->with(["owners","logistics","unit","otherUnit"]);
        if ($id)$query->where("id",$id);
        return $query->paginate(50);
    }

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

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

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

    /**
     * 拷贝目标数据
     *
     * @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 = OwnerPriceLogistic::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 OwnerPriceLogistic $copyModel */
        $copyModel = OwnerPriceLogistic::query()->create($values);

        if ($owners===null){
            $query = DB::raw("SELECT * FROM owner_price_logistic_owner WHERE owner_price_logistic_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_logistic_logistic WHERE owner_price_logistic_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 = ["unit_id", "range", "province_id", "city_id", "unit_price", "delivery_fee", "initial_fee", "initial_amount", "rate",];
                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 OwnerPriceLogisticDetail $item */
                    $obj = $item->toArray();
                    unset($obj["id"]);
                }
                $obj["owner_price_logistic_id"] = $copyModel->id;
                $insert[] = $obj;
            }
        }else{
            foreach ($items as $item){
                $item["owner_price_logistic_id"] = $copyModel->id;
                $insert[] = $item;
            }
        }
        if ($insert)OwnerPriceLogisticDetail::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,OwnerPriceLogistic::query(),$ownerId,$ids);
        if ($result["delete"])$this->destroy($result["delete"]);
        if ($result["update"])OwnerPriceLogistic::query()->whereIn("id",$result["update"])->update(["operation"=>null,"target_id"=>null]);
    }

    public function destroy($id)
    {
        if (!is_array($id))$id = [$id];
        OwnerPriceLogisticDetail::query()->whereIn("owner_price_logistic_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_logistic_owner WHERE owner_price_logistic_id {$query}";
        $owners = array_column(DB::select(DB::raw($sql)),"owner_id");
        DB::table("owner_price_logistic_owner")->whereIn("owner_price_logistic_id",$id)->delete();
        app("OwnerService")->refreshRelevance($owners,3,true);
        DB::table("owner_price_logistic_logistic")->whereIn("owner_price_logistic_id",$id)->delete();

        return OwnerPriceLogistic::destroy($id);
    }

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

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

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

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

    public function checkRange($range):bool
    {
        $arrRanges = explode(",",$range);
        $len = count($arrRanges);
        if ($len==0)return false;   //范围为空 false
        $previous = []; //慢指针数组 不记录第一个值
        foreach ($arrRanges as $index => $value){
            if ($index == $len-1)$preg = "/\d*\-/"; //最后一个范围不允许封闭
            else $preg = "/\d*\-\d*/";
            preg_match($preg, $value, $match);
            if (!$match || $match[0]!=$value)return false;//匹配结果不等于值 false
            $arr = explode("-",$value); //二次切割判断是否连续
            if ($index != 0){
                if ($index == $len-1){
                    if ((int)$arr[0] != (int)$previous[$index-1][1])return false; //最后一个范围只需要判断起始值
                }else{
                    if ((int)$arr[0] != (int)$previous[$index-1][1] || (int)$arr[1] <= (int)$arr[0])return false; //普通范围起始值必须为上一个结束值 当前结束值必须大于起始值
                }
            }else{
                if ((int)$arr[1] <= (int)$arr[0])return false; //第一个范围只需判断当前结束值大于起始值
            }
            $previous[] = $arr;
        }
        return true;
    }

    /**
     *
     * @param double $amount
     * @param integer $owner_id
     * @param integer $logistic_id
     * @param integer $unit_id
     * @param integer $province_id
     * @param integer $city_id
     * @return array
     */
    public function matching($amount, $owner_id, $logistic_id, $unit_id, $province_id, $city_id)
    {
        $model = OwnerPriceLogistic::query()->with(["details"=>function($query)use($province_id,$city_id){
            /** @var Builder $query */
            $query->where("province_id",$province_id)->where("city_id",$city_id);
        }])->where(function ($query)use($unit_id){
            /** @var Builder $query */
            $query->where("unit_id",$unit_id)->orWhere("other_unit_id",$unit_id);
        })->whereHas("owners",function ($query)use($owner_id){
            /** @var Builder $query */
            $query->where("id",$owner_id);
        })->whereHas("logistics",function ($query)use($logistic_id){
            /** @var Builder $query */
            $query->where("id",$logistic_id);
        })->where(function(Builder $query){
            $query->whereNull("operation")->orWhere("operation","");
        })->first();
        if (!$model || !$model->details)return array(null,null);
        $money = null;
        $fee = $model->pick_up_price + $model->fuel_price + $model->service_price; //服务费
        foreach ($model->details as $detail){
            if ($unit_id != $detail->unit_id)continue;
            $arr = explode("-",$detail->range);
            if (count($arr) < 2 || !$arr[1]){
                if ($amount >= $arr[0])$money = $this->calculation($amount,$detail,$fee);
            }else{
                if ($amount >= $arr[0] && $amount < $arr[1])$money = $this->calculation($amount,$detail,$fee);
            }
            if ($money)break;
        }
        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);
    }

    private function calculation($amount, $detail, $fee)
    {
        if ($amount < $detail->initial_amount)$amount = $detail->initial_amount; //小于起始数以起始数为准
        $money = $amount * $detail->unit_price;
        if ($money < $detail->initial_fee)$money = $detail->initial_fee; //小于起始计费以起始计费为准
        return $money+$detail->delivery_fee+$fee;
    }
}
