<?php

namespace app\controller\manager\mall;

use app\controller\manager\Base;
use app\exception\RepositoryException;
use app\model\Config;
use app\model\Log;
use app\model\mall\SpuCategoryPivot;
use app\model\Sku;
use app\model\Spu as SpuModel;
use app\repository\SpuRepository;
use app\service\Math;
use Exception;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use think\exception\ValidateException;
use think\facade\Db;
use think\response\Json;
use think\response\View;

class Spu extends Base
{
    protected $noNeedRight = ['getSpuList', 'getSkuList', 'checkActivity', 'getSpu'];

    /**
     * @throws ModelNotFoundException
     * @throws DbException
     * @throws DataNotFoundException
     * @throws Exception
     */
    public function index()
    {
        if ($this->request->isPost()) {
            $params = input();

            $res = SpuRepository::getInstance()->list($params);

            $res['list'] = $res['list']->each(function ($item) {
                $text = $item->saleable ? '已上架' : '已下架';
                if ($item->is_activity > 0) {
                    $activityText = SpuModel::activityTextList()[$item->activity_type];
                    $text         = '<span style="color: red;">'.$text.' '.$activityText.'中</span>';
                }

                $item->saleable_text = $text;
            });

            return $this->json(0, 'success', $res);
        }

        $this->data['mpPath'] = Config::MINI_PATH_SPU_INFO;;
        $this->data['statusList']  = SpuModel::statusTextList();
        $this->data['spuTypeList'] = SpuModel::spuTypeTextList();

        return $this->view();
    }

    /**
     * @throws ModelNotFoundException
     * @throws DbException
     * @throws DataNotFoundException
     * @throws Exception
     */
    public function score()
    {
        if ($this->request->isPost()) {
            $params         = input();
            $params['type'] = SpuModel::TYPE_SCORE;

            $res = SpuRepository::getInstance()->list($params);

            $res['list'] = $res['list']->each(function ($item) {
                $text                = $item->saleable ? '已上架' : '已下架';
                $item->saleable_text = $text;
            });
            return $this->json(0, 'success', $res);
        }

        $this->data['mpPath'] = Config::MINI_PATH_SPU_INFO;;

        $this->data['statusList']  = SpuModel::statusTextList();
        $this->data['spuTypeList'] = SpuModel::spuTypeTextList();
        $this->data['url']         = '/manager/mall/spu/score';
        $this->data['type']        = SpuModel::TYPE_SCORE;

        return $this->view('manager/mall/spu/index');
    }

    /**
     * 添加
     *
     * @return Json|View
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    public function add()
    {
        $repo = SpuRepository::getInstance();
        $type = input('type', SpuModel::TYPE_NORMAL);
        if ($this->request->isPost()) {
            $item = $this->request->param('item/a', []);

            $item['is_score']      = $type == SpuModel::TYPE_SCORE;
            $item['is_activity']   = in_array($type, SpuModel::activityList());
            $item['activity_type'] = $type;

            $multiSpec           = input('post.is_attribute');// 是否多规格 0否 1是
            $skus                = input('post.skus');//规格数据
            $item['spu_type_id'] = input('post.product_type');//商品类型ID
            $item['multi_spec']  = $multiSpec;

            if ($multiSpec == SpuModel::COMMON_OFF) {
                $skus = [$skus];
            }
            try {
                $this->checkData($item, $skus);

                $repo->addSpu($item, $skus);
            } catch (RepositoryException $e) {
                return $this->json(4002, $e->getMessage());
            } catch (Exception $e) {
            }

            return $this->json();
        }

        $categoryList = $repo->categoryXmSelect([], [], true);

        $this->data['statusList']   = SpuModel::statusTextList();
        $this->data['spuTypeList']  = SpuModel::spuTypeTextList();
        $this->data['limitList']    = SpuModel::limitList();
        $this->data['categoryJson'] = json_encode($categoryList, JSON_UNESCAPED_UNICODE);
        $this->data['type']         = $type;
        $this->data['isScore']      = $type === SpuModel::TYPE_SCORE;

        return $this->view();
    }

    /**
     * 检测商品是否处于活动
     *
     * @return Json
     * @throws RepositoryException
     */
    public function checkActivity(): Json
    {
        $repo = SpuRepository::getInstance();
        $id   = $this->request->param('id/d', 0);
        $spu  = $repo->findById($id);
        if (empty($spu)) {
            return $this->json(4000, '没有相关的商品记录!');
        }

        if ($spu->is_activity > 0) {
            $activityText = SpuModel::activityTextList()[$spu['activity_type']] ?? '';
            $msg          = '该商品正在参与'.$activityText.'活动 无法进行此操作!';
            return $this->json(4000, $msg);
        }

        return $this->json();
    }

    /**
     * @throws DataNotFoundException
     * @throws ModelNotFoundException
     * @throws DbException|RepositoryException
     */
    public function edit()
    {
        $repo = SpuRepository::getInstance();
        $id   = $this->request->param('id/d', 0);
        $spu  = $repo->findById($id);
        if (empty($spu)) {
            return $this->json(4000, '没有相关的商品记录!');
        }

        if ($spu->is_activity > 0) {
            $activityText = SpuModel::activityTextList()[$spu['activity_type']] ?? '';
            $msg          = '该商品正在参与'.$activityText.'活动 无法进行此操作!';
            if ($this->request->isPost()) {
                return $this->json(4000, $msg);
            } else {
                return $this->error($msg);
            }
        }

        $skuList = Sku::where('spu_id', $id)
            ->where('spu_activity_id', 0)
            ->where('enable', Sku::COMMON_ON)
            ->order('sort', 'asc')
            ->order('id', 'asc')->select()->toArray();

        if ($this->request->isPost()) {
            $item                = $this->request->param('item/a', []);
            $multiSpec           = input('post.is_attribute');// 是否多规格 0否 1是
            $skus                = input('post.skus');//规格数据
            $item['spu_type_id'] = input('post.product_type');//商品类型ID
            $item['multi_spec']  = $multiSpec;

            if ($multiSpec == SpuModel::COMMON_OFF) {
                $skus = [$skus];
            }

            try {
                $this->checkData($item, $skus);

                $repo->editSpu($id, $item, $skus, $skuList);
            } catch (RepositoryException $e) {
                return $this->json(4002, $e->getMessage());
            } catch (Exception $e) {
            }

            return $this->json();
        }

        $hasCategories = SpuCategoryPivot::where('spu_id', $id)->column('category_id');
        $categoryList  = $repo->categoryXmSelect($hasCategories, [], true);

        $this->data['statusList']   = SpuModel::statusTextList();
        $this->data['spuTypeList']  = SpuModel::spuTypeTextList();
        $this->data['limitList']    = SpuModel::limitList();
        $this->data['categoryJson'] = json_encode($categoryList, JSON_UNESCAPED_UNICODE);
        $this->data['isScore']      = $spu->is_score;
        $this->data['item']         = $spu;
        $this->data['skuList']      = $skuList;
        $this->data['id']           = $id;
        return $this->view();
    }

    /**
     * 检查数据
     *
     * @throws RepositoryException
     * @throws Exception
     */
    protected function checkData(array $item, array $skus)
    {
        // 基础信息验证
        $validate = $this->validateByApi($item, [
            'name|商品名称'         => 'require|max:250',
            'cover|商品封面'        => 'require|max:250',
            'saleable|商品状态'     => 'in:0,1',
            'published_at|发布日期' => 'requireIf:saleable,1|date',
            'subtitle|副标题'      => 'max:2000',
        ]);

        if ($validate !== true) {
            return $validate;
        }

        if (empty($skus)) {
            throw new RepositoryException('规格信息不能为空');
        }

        foreach ($skus as $k) {
            if ($this->validateSku($k) !== true) {
                return $validate;
            }
        }

        return $validate;
    }

    /**
     * 获取验证结果
     *
     * @param $sku
     * @return bool|Json
     * @throws Exception
     */
    protected function validateSku($sku)
    {
        return $this->validateByApi($sku, [
            'stock'          => 'require|number|gt:0',
            'original_price' => 'number',
            'price'          => 'number',
            'score'          => 'number',
            'is_default'     => 'require|in:0,1',
        ]);
    }

    /**
     * @throws ModelNotFoundException
     * @throws DbException
     * @throws DataNotFoundException
     * @throws Exception
     */
    public function modify()
    {
        if (!$this->request->isPost()) {
            return $this->json(4000, '非法请求');
        }

        $item     = input('post.');
        $validate = $this->validateByApi($item, [
            'field' => 'require',
            'value' => 'require',
        ]);

        if ($validate !== true) {
            return $validate;
        }

        if (!$info = SpuModel::findById($item['id'])) {
            return $this->json(4001, '记录不存在');
        }

        if ($item['field'] == 'home_display') {
            $v             = $item['value'] == 1 ? 'big' : 'normal';
            $item['value'] = $v;
        }

        $update = [$item['field'] => $item['value']];

        try {
            $info->save($update);
            return $this->json();
        } catch (ValidateException $e) {
            return $this->json(4001, $e->getError());
        } catch (Exception $e) {
            return $this->json(5000, '修改失败');
        }
    }

    /**
     * @return Json
     */
    public function del(): Json
    {
        if (!$this->request->isPost()) {
            return $this->json(4000, '非法请求');
        }

        $ids = $this->request->param('ids/a', []);
        if (empty($ids)) {
            $ids[] = $this->request->param('id/d', 0);
            $ids   = array_filter($ids);
        }

        try {
            if (count($ids)) {
                $count = SpuModel::whereIn('id', $ids)
                    ->where('is_activity|saleable', SpuModel::COMMON_ON)
                    ->count();
                if ($count > 0) {
                    return $this->json(4002, '当前商品状态不可删除!');
                }

                SpuRepository::getInstance()->deleteSpu($ids);
                Log::write(get_class(), 'del', '删除了商品信息,涉及到的ID为:'.implode(',', $ids));
            }
        } catch (RepositoryException $e) {
            return $this->json(4001, $e->getMessage());
        }

        return $this->json();
    }

    /**
     * 商品详情
     */
    public function info()
    {
        $skuId = $this->request->param('id/d', 0);
        $repo  = SpuRepository::getInstance();
        try {
            $sku = $repo->findById($skuId, []);
        } catch (RepositoryException $e) {
            $sku = null;
        }

        $this->data['item'] = $sku;
        return $this->view();
    }

    /**
     * 商品状态下拉选项
     *
     * @param  array  $selected
     * @param  array  $disabled
     * @return false|string
     */
    private function handleXmStatus(array $selected = [], array $disabled = [])
    {
        $items = SpuModel::statusTextList();
        $list  = [];
        foreach ($items as $key => $val) {
            $list[] = [
                'name'     => $val,
                'value'    => $key,
                'selected' => in_array($key, $selected),
                'disabled' => in_array($key, $disabled),
            ];
        }
        return json_encode($list, JSON_UNESCAPED_UNICODE);
    }

    /**
     * @throws Exception
     */
    public function getSpuList(): Json
    {
        if ($this->request->isPost()) {
            $input = [
                'type'     => SpuModel::TYPE_NORMAL,
                'saleable' => SpuModel::COMMON_ON,
                'keyword'  => input('keyword/s', '')
            ];
            $data  = SpuRepository::getInstance()->list($input);
            return $this->json(0, 'success', $data);
        }

        return $this->json(4000, '操作错误');
    }

    /**
     * @throws Exception
     */
    public function getSpu(): Json
    {
        if ($this->request->isPost()) {
            $id   = input('id/d');
            $data = SpuModel::findById($id, ['id', 'spu_type_id', 'multi_spec']);
            return $this->json(0, 'success', $data);
        }

        return $this->json(4000, '操作错误');
    }

    /**
     * @throws Exception
     */
    public function getSkuList(): Json
    {
        if ($this->request->isPost()) {
            $spuId = input('id/d', 0);
            $data  = Sku::where('spu_id', $spuId)->select();
            $data  = $data->each(function ($item) {
                $item->original_price = Math::fen2Yuan($item->original_price);
                $item->price          = Math::fen2Yuan($item->price);
            });
            return $this->json(0, 'success', $data);
        }

        return $this->json(4000, '操作错误');
    }

    /**
     * 批量审核
     *
     * @return View|Json
     * @throws Exception
     */
    public function check()
    {
        $id = input('id/s', '');
        if ($this->request->isPost()) {
            $ids   = input('ids/s');
            $check = input('is_check/d');

            if (!in_array($check, [SpuModel::COMMON_ON, SpuModel::COMMON_OFF])) {

                return $this->json(4001, '请选择是否展示');
            }

            $ids = explode(',', $ids);

            Db::startTrans();
            try {
                (new SpuModel())->whereIn('id', $ids)->save(['is_check' => $check]);
                Db::commit();
                return $this->json(0, '操作成功');
            } catch (Exception $e) {
                Db::rollback();
                Log::error('商品批量审核操作失败'.$e->getMessage());
                return $this->json(5001, '商品批量审核操作失败');
            }
        }

        $this->data['id'] = $id;

        return $this->view();
    }

}