<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);

namespace app\common\library\collector\provider\driver;

use app\common\enum\goods\SpecType as GoodsSpecTypeEnum;
use app\common\library\collector\provider\Driver;
use cores\exception\BaseException;

/**
 * 京东商品采集驱动
 * Class Jd
 * @package app\common\library\collector\provider\driver
 */
class Jd extends Driver
{
    // API地址
    const API_URL = 'https://api09.99api.com/jd/detail';

    /**
     * 获取商品详情
     * @param string $itemId
     * @return array
     * @throws BaseException
     */
    public function detail(string $itemId): array
    {
        $result = $this->curlGet(self::API_URL, $itemId);
        return $this->formatGoods($result['data']);
    }

    /**
     * 格式化商品数据
     * @param array $original
     * @return array
     */
    private function formatGoods(array $original): array
    {
        $data = [];
        // 商品规格 (SKU数量为1时是单规格,大于1是多规格)
        $data['spec_type'] = \count($original['item']['sku']) > 1 ? GoodsSpecTypeEnum::MULTI : GoodsSpecTypeEnum::SINGLE;
        $data['goods_name'] = $original['item']['name'];
        $data['goodsImages'] = $this->goodsImages($original['item']['images']);
        $data['content'] = $this->goodsContent($original['item']['descImgs']);
        // 商品价格
        $price = $original['item']['price'];
        // 规格组封面图
        $clothesColor = $original['item']['clothesColor'] ?? [];
        // 整理多规格数据
        if ($data['spec_type'] === GoodsSpecTypeEnum::MULTI) {
            $skuProps = $this->skuProps($original['item']['skuProps']);
            $saleProp = $this->saleProp($original['item']['saleProp'], \count($skuProps));
            $specList = $this->createSpecList($saleProp, $skuProps);
            $data['specData']['specList'] = $specList;
            $data['specData']['skuList'] = $this->createSkuList($original['item']['sku'], $specList, $price, $clothesColor);
        } elseif ($data['spec_type'] === GoodsSpecTypeEnum::SINGLE) {
            $data['goods_price'] = $price;
            $data['line_price'] = '0.00';
            $data['stock_num'] = 100;    // 库存默认100
            $data['goods_weight'] = 1;    // 重量默认1kg
        }
        return $data;
    }

    /**
     * 创建标准的商品SKU数据
     * @param array $originalSkuList 商品SKU列表
     * @param array $specList 商品规格
     * @param string $price 商品价格
     * @param array $clothesColor 规格组封面图
     * @return array
     */
    private function createSkuList(array $originalSkuList, array $specList, string $price, array $clothesColor): array
    {
        // 根据规格数据生成完整的SKU数据 (因为originalSkuList会有不存在的sku)
        $cartesian = $this->cartesian($specList);
        // 整理商品SKU列表
        $skuList = [];
        foreach ($cartesian as $spec) {
            // 设置skuKeys数据
            $skuKeys = [];
            foreach ($spec as $specValue) {
                $skuKeys[] = [
                    'groupKey' => $specValue['groupKey'],
                    'valueKey' => $specValue['key']
                ];
            }
            // 查找已存在的SKU
            $originalSku = $this->findOriginalSku($originalSkuList, $spec);
            // 整理SKU数据
            $skuList[] = [
                'image_id' => 0,
                'goods_price' => $price,
                'line_price' => '0.00',
                'stock_num' => 100,    // 库存默认100
                'goods_weight' => 1,    // 重量默认1kg
                'goods_sku_no' => $originalSku ? $originalSku['skuId'] : '',
                'skuKeys' => $skuKeys,
                'imageUrl' => $this->findClothesColor($clothesColor, $spec),
            ];
        }
        return $skuList;
    }

    /**
     * 查找SKU封面图
     * @param array $clothesColor
     * @param array $spec
     * @return string
     */
    private function findClothesColor(array $clothesColor, array $spec): string
    {
        foreach ($spec as $skuValue) {
            if ($skuValue['groupKey'] != 0) {
                continue;
            }
            foreach ($clothesColor as $item) {
                if ($skuValue['spec_value'] === $item['color']) {
                    return $this->imageUrl($item['imagePath']);
                }
            }
        }
        return '';
    }

    /**
     * 格式化图片url
     * @param string $url
     * @return string
     */
    private function imageUrl(string $url): string
    {
        if (empty($url)) {
            return '';
        }
        // 京东商品规格图不使用缩略图处理
        if (\strpos($url, 's40x40_jfs')) {
            $url = str_replace('s40x40_jfs', 's750x750_jfs', $url);
        }
        // 补全url协议
        if (\substr($url, 0, 2) === '//') {
            return "https:{$url}";
        }
        if (\substr($url, 0, 4) != 'http') {
            return "https://{$url}";
        }
        // http替换为https
        return str_replace('http://', 'https://', $url);
    }

    /**
     * 查找已存在的SKU
     * @param array $originalSkuList
     * @param array $spec
     * @return false|mixed
     */
    private function findOriginalSku(array $originalSkuList, array $spec)
    {
        foreach ($originalSkuList as $item) {
            $temp = 0;
            foreach ($spec as $specValue) {
                if ($item[$specValue['groupKey'] + 1] == $specValue['spec_value']) {
                    $temp++;
                }
            }
            if ($temp === \count($spec)) {
                return $item;
            }
        }
        return false;
    }

    /**
     * 生成完整的SKU列表(笛卡尔积运算)
     * @param array $specList
     * @param array $tmp
     * @param array $nArr
     * @return int
     */
    private function cartesian(array $specList, array $tmp = [], array $nArr = [])
    {
        foreach (array_shift($specList)['valueList'] as $v) {
            $tmp[] = $v;
            if ($specList) {
                $nArr = $this->cartesian($specList, $tmp, $nArr);
            } else {
                $nArr[] = $tmp;
            }
            array_pop($tmp);
        }
        return $nArr;
    }

    /**
     * 创建标准的商品规格数据(树状)
     * @param array $saleProp 规格组
     * @param array $skuProps 规格值
     * @return array
     */
    private function createSpecList(array $saleProp, array $skuProps): array
    {
        $specList = [];
        foreach ($saleProp as $specName) {
            $groupKey = \count($specList);
            $valueList = [];
            foreach ($skuProps[$groupKey] as $specValue) {
                $valueList[] = [
                    'key' => \count($valueList),
                    'groupKey' => $groupKey,
                    'spec_value' => $specValue,
                ];
            }
            $specList[] = [
                'key' => $groupKey,
                'spec_name' => $specName,
                'valueList' => $valueList,
            ];
        }
        return $specList;
    }

    /**
     * 格式化商品规格组
     * @param array $saleProp
     * @param int $count
     * @return array
     */
    private function saleProp(array $saleProp, int $count): array
    {
        ksort($saleProp);
        return \array_slice($saleProp, 0, $count);
    }

    /**
     * 格式化规格值
     * @param array $skuProps
     * @return array
     */
    private function skuProps(array $skuProps): array
    {
        return \array_values(array_filter($skuProps, function ($item) {
            \is_array($item) && $item = \array_values(\array_filter($item));
            return $item ?: null;
        }));
    }

    /**
     * 格式化商品主图
     * @param array $images
     * @return array
     */
    private function goodsImages(array $images): array
    {
        return array_map(function (string $imageUrl) {
            return $this->imageUrl($imageUrl);
        }, \array_slice($images, 0, 10));
    }

    /**
     * 格式化商品详情
     * @param array $descImgs
     * @return string
     */
    private function goodsContent(array $descImgs): string
    {
        $content = '';
        foreach ($descImgs as $img) {
            $content .= "<p><img src=\"{$img}\"/></p>";
        }
        return $content;
    }
}