<?php

namespace App\Modules\Admin\Services;

use App\Base\BaseService;
use App\Exceptions\ClientException;
use App\Models\Goods\Spec;
use App\Models\Goods\SpecAttr;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\DB;
use Nerd\CartesianProduct\CartesianProduct;

class SpecService extends BaseService
{
    public function paginate($params)
    {
        $p = Spec::query()->when($params['name'], function (Builder $query) use ($params) {
            return $query->where("name", 'like', "%{$params['name']}%");
        })->orderByDesc("id")->paginate($params['page_size']);

        return [
            "total" => $p->total(),
            "page_total" => $p->lastPage(),
            "list" => array_map(function (Spec $u) {
                return $u->format(Spec::FORMAT_ATTR);
            }, $p->items()),
        ];
    }

    public function specStore($params)
    {
        $id = $params['id'] ?? 0;
        if ($id) {
            $spec = Spec::find($id);
        } else {
            $spec = new Spec();
        }
        $spec->name = Arr::get($params, 'name');
        $spec->index_weight = Arr::get($params, 'index_weight');
        $spec->category_weight = Arr::get($params, 'category_weight');
        $spec->search_weight = Arr::get($params, 'search_weight');
        $spec->is_custom = (int)Arr::get($params, 'is_custom');

        DB::transaction(function () use ($params, $spec) {
            $spec->save();
            $attr = Arr::get($params, "attr", []);
            $holdIdArr = Arr::pluck($attr, "id");
            SpecAttr::query()->where("spec_id", $spec->id)->whereNotIn("id", $holdIdArr)->delete();

            foreach ($attr as $k => $v) {
                $id = Arr::get($v, "id");
                if ($id) {
                    $m = SpecAttr::whereSpecId($spec->id)->find($id);
                    if (is_null($m)) {
                        logger()->error("无法保存这个属性值:" . $v['name'] ?? "");
                        throw new ClientException("无法保存这个属性值:" . $v['name'] ?? "");
                    }
                } else {
                    $m = new SpecAttr();
                }
                $m->spec_id = $spec->id;
                $m->name = $v['name'] ?? "";
                $m->save();
            }

        });

        return true;
    }

    public function specInfo($data)
    {
        $id = $data['id'];
        $spec = Spec::findOrFail($id);
        return $spec->format(Spec::FORMAT_ATTR);
    }

    public function specDelete($data)
    {
        $id = $data['id'] ?? 0;
        // @TODO kphcdr 判断是否有商品还在使用这个规则,否则无法删除

        $spec = Spec::find($id);
        if ($spec) {
            SpecAttr::where("spec_id", $spec->id)->delete();
            $spec->delete();
        }
        return true;
    }

    /**
     * 生成笛卡尔积表格
     *
     * @param array $specIdArr
     */
    public function cartesian(array $specIdArr)
    {
        $specS = Spec::with("attrs")->whereIn("id", $specIdArr)->get();

        $attrS = collect();
        $cartesianProduct = new CartesianProduct();
        foreach ($specS as $spec) {
            /** @var Spec $spec */
            $cartesianProduct->appendSet($spec->attrs->pluck("name")->toArray());
            $attrS = $attrS->merge($spec->attrs);
        }
        $cartesian = $cartesianProduct->compute();

        foreach ($cartesian as $c) {

            $return[] = [
                "id" => 0,
                "sn" => "",
                "url_3d" => "",
                "is_use" => 1,
                "spec_attr" => array_map(function ($cname) use ($attrS) {
                    return [
                        "id" => $attrS->where("name", $cname)->value("id"),
                        "name" => $cname,
                    ];
                }, $c),
            ];
        }
        return $return;
    }
}