<?php

namespace addons\shopro\service\goods;

use app\admin\model\shopro\goods\Goods;
use app\admin\model\shopro\goods\SkuPrice;
use app\admin\model\shopro\app\ScoreSkuPrice;
use app\admin\model\shopro\Category;
use think\Cache;
use think\Db;
use addons\shopro\library\Tree;
use addons\shopro\service\SearchHistory;
use addons\shopro\facade\Activity as ActivityFacade;

class GoodsService
{
    protected $query = null;
    protected $order = [];
    protected $md5s = [];
    protected $format = null;
    protected $is_activity = false;     // 是否处理活动
    protected $show_score_shop = false;     // 查询积分商城商品

    public function __construct(\Closure $format = null, \think\db\Query $query = null)
    {
        $this->query = $query ?: new Goods();
        $this->format = $format;
    }


    /**
     * with 关联
     *
     * @param mixed $with
     * @return self
     */
    public function with($with) 
    {
        $this->query->with($with);

        return $this;
    }


    /**
     * 查询上架的商品，包含隐藏商品
     *
     * @return self
     */
    public function show()
    {
        $this->md5s[] = 'show';
        $this->query = $this->query->whereIn('status', ['up', 'hidden']);

        return $this;
    }


    /**
     * 查询上架的商品，不包含隐藏商品
     *
     * @return self
     */
    public function up()
    {
        $this->md5s[] = 'up';
        $this->query = $this->query->where('status', 'up');

        return $this;
    }


    /**
     * 是否要处理活动相关数据
     *
     * @return self
     */
    public function activity($activity = false)
    {
        $this->is_activity = $activity ? true : false;

        return $this;
    }


    /**
     * 查询积分商城商品
     *
     * @return self
     */
    public function score() 
    {
        $this->show_score_shop = true;

        // 获取所有积分商品
        $scoreGoodsIds = ScoreSkuPrice::where('status', 'up')->group('goods_id')->cache(60)->column('goods_id');
        $this->query = $this->query->whereIn('id', $scoreGoodsIds);

        return $this;
    }


    /**
     * 连表查询 库存，暂时没用
     *
     * @return self
     */
    public function stock()
    {
        $this->md5s[] = 'stock';

        $skuSql = SkuPrice::field('sum(stock) as stock, goods_id as sku_goods_id')->group('goods_id')->buildSql();
        $this->query = $this->query->join([$skuSql => 'sp'], 'id = sp.sku_goods_id', 'left');

        return $this;
    }



    /**
     * 搜索商品
     *
     * @return self
     */
    public function search($keyword) 
    {
        $keyword = is_string($keyword) ? $keyword : json_encode($keyword);      // 转字符串
        $this->md5s[] = 'search:' . $keyword;           // 待补充

        // 添加搜索记录
        $searchHistory = new SearchHistory();
        $searchHistory->save(['keyword' => $keyword]);

        $this->query = $this->query->where('title|subtitle', 'like', '%' . $keyword . '%');
        return $this;
    }


    /**
     * 根据 ids 获取商品
     *
     * @param string|array $ids ids 数组或者 , 隔开的字符串
     * @return self
     */
    public function whereIds($ids = '') 
    {
        $ids = array_map('intval', is_array($ids) ? $ids : explode(',', (string)$ids));
        $this->md5s[] = 'ids:' . implode(',', $ids);

        if (!empty($ids)) {
            $this->query = $this->query->orderRaw('field(id, ' . implode(',', $ids) . ')');      // 按照 ids 里面的 id 进行排序
            $this->query = $this->query->whereIn('id', $ids);
        }

        return $this;
    }


    /**
     * 根据商品分类获取商品
     *
     * @param integer $category_id
     * @return self
     */
    public function category($category_id, $is_category_deep = true)
    {
        $category_id = intval($category_id);
        $this->md5s[] = 'category_id:' . $category_id;
        $category_ids = [];
        if (isset($category_id) && $category_id != 0) {
            if ($is_category_deep) {
                // 查询分类所有子分类,包括自己
                $category_ids = (new Tree(function () {
                    // 组装搜索条件，排序等
                    return (new Category)->normal();
                }))->getChildIds($category_id);
            } else {
                $category_ids = [$category_id];
            }
        }

        $this->query->where(function ($query) use ($category_ids) {
            // 所有子分类使用 find_in_set or 匹配，亲测速度并不慢
            foreach ($category_ids as $key => $category_id) {
                $query->whereOrRaw("find_in_set($category_id, category_ids)");
            }
        });

        return $this;
    }

    /**
     * 根据多个分类ID查询商品
     *
     * @param array|string $categoryIds 分类ID数组或逗号分隔的字符串
     * @param bool $is_category_deep 是否查询子分类
     * @return self
     */
    public function categories($categoryIds, $is_category_deep = true)
    {
        // 快速路径：空参数直接返回
        if (empty($categoryIds)) {
            return $this;
        }

        // 统一处理输入：字符串转数组，去除空格，转换为整数
        if (is_string($categoryIds)) {
            $categoryIds = array_filter(array_map('intval', array_map('trim', explode(',', $categoryIds))));
        } else {
            $categoryIds = array_filter(array_map('intval', $categoryIds));
        }

        // 去重
        $categoryIds = array_unique($categoryIds);
        if (empty($categoryIds)) {
            return $this;
        }

        $this->md5s[] = 'category_ids:' . implode(',', $categoryIds);

        // 如果需要查询子分类（使用缓存）
        if ($is_category_deep) {
            $allCategoryIds = [];
            $tree = null;

            foreach ($categoryIds as $categoryId) {
                // 构建缓存key
                $cacheKey = "category_child_ids_{$categoryId}";

                // 尝试从缓存获取

                $childIds = Cache::get($cacheKey);

                if ($childIds === false) {
                    // 缓存不存在，查询并缓存
                    if (!$tree) {
                        $tree = new Tree(function () {
                            return (new Category)->normal();
                        });
                    }
                    $childIds = $tree->getChildIds($categoryId);

                    // 缓存24小时
                    Cache::set($cacheKey, $childIds, 86400);
                }

                $allCategoryIds = array_merge($allCategoryIds, $childIds);
            }

            $categoryIds = array_unique($allCategoryIds);
        }

        // 优化：构建单个 WHERE 条件
        $conditions = [];
        foreach ($categoryIds as $categoryId) {
            $conditions[] = "FIND_IN_SET($categoryId, category_ids)";
        }

        $this->query->whereRaw(implode(' OR ', $conditions));

        return $this;
    }

    /**
     * 排序，方法参数同 thinkphp order 方法
     *
     * @param string $sort
     * @param string $order
     * @return self
     */
    public function order($sort = 'weigh', $order = 'desc')
    {
        $sort = $sort == 'price' ? Db::raw('convert(`price`, DECIMAL(10, 2)) ' . $order) : $sort;
        $this->query->order($sort, $order);
        return $this;
    }



    /**
     * 获取商品列表
     *
     * @param bool $is_cache    是否缓存
     * @return array|\think\model\Collection
     */
    public function select($is_cache = false) 
    {
        $this->md5s[] = 'select';

        // 默认排序
        $this->order();

        $goods = $this->query->field('*,(sales + show_sales) as total_sales')
                    ->cache($this->getCacheKey($is_cache), (200 + mt_rand(0, 100)))
                    ->select();

        // 格式化数据
        foreach ($goods as $key => $gd) {
            $gd = $this->defaultFormat($gd);
            if ($this->format instanceof \Closure) {
                $gd = ($this->format)($gd, $this);
            }

            $goods[$key] = $gd;
        }

        return $goods;
    }


    /**
     * 获取商品列表
     *
     * @param bool $is_cache    是否缓存
     * @return \think\Paginator
     */
    public function paginate($is_cache = false) 
    {
        $this->md5s[] = 'paginate';

        // 默认排序
        $this->order();

        $goods = $this->query->field('*,(sales + show_sales) as total_sales')
                    ->cache($this->getCacheKey($is_cache), (200 + mt_rand(0, 100)))
                    ->paginate(request()->param('list_rows', 10));

        // 格式化数据
        $goods->each(function($god) {
            $god = $this->defaultFormat($god);
            if ($this->format instanceof \Closure) {
                ($this->format)($god, $this);
            }
        });

        return $goods;
    }

    /**
     * 获取AI试戴饰品列表
     *
     * @param bool $is_cache    是否缓存
     * @return \think\Paginator
     */
    public function jewelryPaginate($allowed_cate_ids, $is_cache = false)
    {
        $this->md5s[] = 'paginate';

        // 确保分类ID不为空
        if (empty($allowed_cate_ids)) {
            // 返回空的分页结果
            $this->query->where('id', 0);
        }

        // 默认排序
        $goods = $this->up()
            ->categories($allowed_cate_ids)
            ->whereNotNull('image_3d')
            ->where('image_3d', '<>', '')
            ->order('id', 'desc')
            ->paginate($is_cache);
        return $goods;
    }



    /**
     * 获取单个商品
     *
     * @param bool $is_cache
     * @return Goods
     */
    public function find($is_cache = false)
    {
        $this->md5s[] = 'find';
        $goods = $this->query->cache($this->getCacheKey($is_cache), (200 + mt_rand(0, 100)))->find();

        if ($goods && $this->format instanceof \Closure) {
            // 格式化数据
            $goods = $this->defaultFormat($goods);
            ($this->format)($goods, $this);
        }

        return $goods;
    }


    /**
     * 获取单个商品,找不到抛出异常
     *
     * @param bool $is_cache
     * @return Goods
     */
    public function findOrFail($is_cache = false)
    {
        $this->md5s[] = 'find';
        $goods = $this->query->cache($this->getCacheKey($is_cache), (200 + mt_rand(0, 100)))->find();
        if (!$goods) {
            error_stop('商品不存在');
        }

        if ($this->format instanceof \Closure) {
            // 格式化数据
            $goods = $this->defaultFormat($goods);
            ($this->format)($goods, $this);
        }

        return $goods;
    }



    /**
     * 把活动相关数据覆盖到商品
     *
     * @param array|object $goods
     * @return array
     */
    public function defaultFormat($goods) 
    {
        $skuPrices = $goods->sku_prices;
        $activity = $this->is_activity ? $goods->activity : null;

        if ($activity) {
            $skuPrices = ActivityFacade::recoverSkuPrices($goods, $activity);
            // unset($goods['activity']['activity_sku_prices']);        // db 获取活动这里删除报错
        }

        if ($this->show_score_shop) {
            $scoreSkuPrices = $goods->all_score_sku_prices;     // 包含下架的积分规格

            // 积分商城，覆盖积分商城规格
            foreach ($skuPrices as $key => &$skuPrice) {
                $stock = $skuPrice->stock;      // 下面要用
                $skuPrice->stock = 0;
                $skuPrice->sales = 0;
                foreach ($scoreSkuPrices as $scoreSkuPrice) {
                    if ($skuPrice->id == $scoreSkuPrice->goods_sku_price_id) {
                        $skuPrice->stock = ($scoreSkuPrice->stock > $stock) ? $stock : $scoreSkuPrice->stock;     // 积分商城库存不能超过商品库存
                        $skuPrice->sales = $scoreSkuPrice->sales;
                        $skuPrice->price = $scoreSkuPrice->price;
                        $skuPrice->score = $scoreSkuPrice->score;
                        $skuPrice->status = $scoreSkuPrice->status;        // 采用积分的上下架

                        // $skuPrice->score_price = $scoreSkuPrice->score_price;

                        // 记录对应活动的规格的记录
                        $skuPrice->item_goods_sku_price = $scoreSkuPrice;
                        break;
                    }
                }
            }
        }

        // 移除下架的规格
        foreach ($skuPrices as $key => $skuPrice) {
            if ($skuPrice['status'] != 'up') {
                unset($skuPrices[$key]);
            }
        }
        $skuPrices = $skuPrices instanceof \think\Collection ? $skuPrices->values() : array_values($skuPrices);

        if ($activity) {
            // 处理活动相关的价格，销量等

            // 这里由 getPriceAttr 计算,这里后续删除
            // $prices = $skuPrices instanceof \think\Collection ? $skuPrices->column('price') : array_column($skuPrices, 'price');
            // $goods['price'] = $prices ? min($prices) : $goods['price'];      // min 里面不能是空数组

            // if ($activity['type'] == 'groupon') {
            //     $grouponPrices = $skuPrices instanceof \think\Collection ? $skuPrices->column('groupon_price') : array_column($skuPrices, 'groupon_price');
            //     $goods['groupon_price'] = $grouponPrices ? min($grouponPrices) : $goods['price'];
            // }

            // if ($activity['type'] == 'groupon_ladder') {
            //     // @sn 阶梯拼团，商品详情如何显示拼团价格，阶梯拼团
            // }

            // if ($activity['rules'] && isset($activity['rules']['sales_show_type']) && $activity['rules']['sales_show_type'] == 'real') {
            //     // 活动设置显示真实销量
            //     $goods['sales'] = array_sum($skuPrices instanceof \think\Collection ? $skuPrices->column('sales') : array_column($skuPrices, 'sales'));
            // } else {
            //     // 活动显示总销量
            //     $goods['sales'] += $goods['show_sales'];
            // }
        } elseif ($this->show_score_shop) {
            // 积分商城这里显示的是真实销量， 目前都由 getSalesAttr 计算
            // $goods['sales'] = array_sum($skuPrices instanceof \think\Collection ? $skuPrices->column('sales') : array_column($skuPrices, 'sales'));
        } else {
            // 没有活动，商品销量，加上虚增销量
            // $goods['sales'] += $goods['show_sales'];
        }

        if ($this->show_score_shop) {
            // 积分商城商品
            $goods['show_score_shop'] = $this->show_score_shop;
        }

        // 不给 sku_prices 赋值，会触发 getSkuPricesAttr 计算属性，覆盖计算好的 sku_prices| 但是这样 sku_prices 会存在下标不连续的情况
        $goods['new_sku_prices'] = $skuPrices;       // 商品详情接口用， 过滤掉了 下架的规格
        // $goods['sales'] = $goods->salesStockFormat($goods['sales'], $goods['sales_show_type']);        // 格式化销量，前端格式化，这里可删除
        $stocks = $skuPrices instanceof \think\Collection ? $skuPrices->column('stock') : array_column($skuPrices, 'stock');        // 获取规格中的库存
        $stock = array_sum($stocks);
        $goods['stock'] = $stock;
        // $goods['stock'] = $goods->salesStockFormat($stock, $goods['stock_show_type']);                 // 格式化库存，前端格式化，这里可删除
        $goods['activity_type'] = $activity['type'] ?? null;
        return $goods;
    }



    /**
     * 获取缓存 key
     *
     * @param bool $is_cache    是否缓存
     * @return string|bool
     */
    protected function getCacheKey($is_cache = false)
    {
        if ($is_cache) {
            sort($this->md5s);
            $key = 'goods-service-' . md5(json_encode($this->md5s));
        }

        return $key ?? false;
    }



    /**
     * 默认调用 query 中的方法，比如 withTrashed()
     *
     * @param [type] $funcname
     * @param [type] $arguments
     * @return void
     */
    public function __call($funcname, $arguments)
    {
        $this->query->{$funcname}(...$arguments);

        return $this;
    }

    /**
     * 判断商品分类是否在允许的分类ID数组中
     *
     * @param int $goodId 商品ID
     * @param int $categoryIds 商品分类ID
     * return int
     */
    public function isCategoryAllowed($categoryIds, $goodId=0)
    {
        if (empty($categoryIds) && empty($goodId)) {
            return 0;
        }

        if (empty($categoryId) && !empty($goodId)) {
            $goods = $this->whereIds($goodId)->find();
            $categoryIds = $goods['category_ids'] ?? 0;
        }

        $count = 0;
        if (!empty($categoryIds)){
            // 获取配置的允许分类ID数组
            $allowedCates = config('shopro.allow_tryon_cate');
            if (empty($allowedCates)) {
                return 0;
            }

            // 将配置字符串转换为数组
            $allowedArray = explode(',', $allowedCates);

            $categoryIdsArray = explode(',', $categoryIds);
            // 去除空格并转换为整数
            $categoryIdsArray = array_map(function ($item) {
                return (int)trim($item);
            }, $categoryIdsArray);

            // 判断当前分类ID是否在允许列表中
            $count = count(array_intersect($allowedArray, $categoryIdsArray));
        }

        return $count > 0 ? 1 : 0;
    }


    /**
     * 判断商品分类是否在AI试戴的分类ID数组中
     *
     * @param string $cateIds 商品分类IDS
     * @param string $allowCateIds AI允许试戴分类IDS
     * return int
     */
    public function isCateAllowedAi($cateIds, $allowCateIds)
    {
        if (empty($cateIds) || empty($allowCateIds)) {
            return 0;
        }

        $cateIdArray = array_map('trim', explode(',', $cateIds));
        $allowIdArray = array_map('trim', explode(',', $allowCateIds));

        foreach ($cateIdArray as $cateId) {
            if (in_array($cateId, $allowIdArray)) {
                return 1;
            }
        }

        return 0;
    }

}
