<?php
use GuzzleHttp\Client;
use GuzzleHttp\Cookie\FileCookieJar;

class zhiPeiAction extends baseAction
{
    public $oClient = null;
    public $oFactory = null;
    public $oCookie = null;

    public function index()
    {
        $aParam = mvc::$URL_PARAMS;
        // $aParam = ['user' => '帕夫斯特', 'pass' => '51CJML'];
        if ($aParam['user'] && $aParam['pass'])
        {
            $aOption = [
                'user' => $aParam['user'],
                'pass' => $aParam['pass'],
            ];
            $aResult = $this->product($aOption);
            LibTpl::Set('Return', $aResult['data']);
        }

        LibTpl::Set('aParam', $aParam);
        LibTpl::Set('title', '智配转数据');
        LibTpl::Put();
    }

    public function forSleep($sMin = 0, $sMax = 7) {
        return sleep(rand($sMin, $sMax));
    }

    /**
     * cookies
     */
    public function cookies($sUser = '', $sPass = '51CJML')
    {
        $oClient = new Client([
            'debug' => false,
            'timeout' => 60,
            'cookies' => true,
            'base_uri' => 'https://www.51cjml.com',
            'headers' => [
                'Content-Type' => 'application/x-www-form-urlencoded; charset=UTF-8',
                'Origin' => 'https://www.51cjml.com',
                'Host' => 'www.51cjml.com',
                'Referer' => 'https://www.51cjml.com/factory/',
                'User-Agent' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36',
                'X-Requested-With' => 'XMLHttpRequest'
            ]
        ]);

        $sReturn = false;
        $sCookiePath =sprintf('%s/cookies', mvc::$cfg['ZHIPEI']['storage']);
        $sCookieFile = sprintf('%s/%d.cookie', $sCookiePath, time());
        if (!is_dir($sCookiePath)) {
            LibDir::CreateDir($sCookiePath);
        }
        $oCookieJar = new FileCookieJar($sCookieFile, true);
        try
        {
            $oGuzzle = $oClient->post('/factory/Home/UserLogin', [
                'cookies' => $oCookieJar,
                'form_params' => [
                    'UserName' => $sUser,
                    'PassWord' => $sPass,
                    'IsRememeber' => 1,
                ]
            ]);
            if ($oGuzzle->getStatusCode() == 200)
            {
                $sReturn = true;
                $this->oClient = $oClient;
                $this->oCookie = $oCookieJar;

                $this->oFactory = new Client([
                    'timeout' => 60,
                    'cookies' => true,
                    'base_uri' => 'https://factory.51cjml.com',
                    'headers' => [
                        'content-type' => 'application/json',
                        'authorization' => $oCookieJar->getCookieByName('YC51_AutoCategory_Manufacturer_UserTicket')->getValue()
                    ]
                ]);
            }
        } catch (\GuzzleHttp\Exception\TransferException $e) {}
        return $sReturn;
    }

    /**
     * 采集产品列表
     */
    public function product($aOption = [])
    {
        set_time_limit(0);
        ini_set('memory_limit', '2048M');

        $aReturn = ['status' => false, 'data' => 'false'];
        if (!$aOption['user'] || !$aOption['pass'])
        {
            $aReturn['data'] = '账号不能为空';
            return $aReturn;
        }
        $sStorge = sprintf('%s/%d_%s', mvc::$cfg['ZHIPEI']['storage'], date('Ymd'), $aOption['user']);

        // product
        $sProduct = sprintf('%s/product.json', $sStorge);
        if (!is_file($sProduct))
        {
            if (is_null($this->oClient))
            {
                $sResult = $this->cookies($aOption['user'], $aOption['pass']);
                if (!$sResult)
                {
                    $aReturn['data'] = '账号登录失败';
                    return $aReturn;
                }
            }

            $sEnd = 99;
            $perPage = 500;
            for ($sGet = 0; $sGet < 3; $sGet ++)
            {
                for ($sRun = 1; $sRun <= $sEnd; $sRun ++)
                {
                    $sFile = sprintf('%s/product/%d.json', $sStorge, $sRun);
                    if (is_file($sFile))
                    {
                        $aGuzzle = json_decode(file_get_contents($sFile), true);
                        $sEnd = ceil($aGuzzle['result']['pageInfo']['Rows'] / $perPage);
                        continue;
                    }

                    try
                    {
                        $oGuzzle = $this->oClient->post('/factory/PartItem/GetPartItemByPage', [
                            'cookies' => $this->oCookie,
                            'form_params' => [
                                'PartsNo' => '',
                                'AuditStatus' => 1,
                                'PageIndex' => $sRun,
                                'PageSize' => $perPage,
                                'isHaveImage' => '',
                                'isHaveParam' => '',
                                'barCode' => '',
                            ],
                        ]);
                        if (200 == $oGuzzle->getStatusCode())
                        {
                            $sGuzzle = $oGuzzle->getBody()->getContents();
                            $aGuzzle = json_decode($sGuzzle, true);
                            if (isset($aGuzzle['message']) && ($aGuzzle['message'] == '执行成功'))
                            {
                                $sEnd = ceil($aGuzzle['result']['pageInfo']['Rows'] / $perPage);
                                LibDir::CreateDir(pathinfo($sFile, PATHINFO_DIRNAME));
                                file_put_contents($sFile, $sGuzzle);
                            }
                        }
                    } catch (\GuzzleHttp\Exception\TransferException $oTransfer) {}
                    $this->forSleep();
                }
            }

            // 合并产品列表
            $aProduct = [];
            for ($sRun = 1; $sRun <= $sEnd; $sRun ++)
            {
                $sFile = sprintf('%s/product/%d.json', $sStorge, $sRun);
                if (!is_file($sFile))
                {
                    $aReturn['data'] = '采集产品列表异常';
                    return $aReturn;
                }

                $aJson = json_decode(file_get_contents($sFile), true);
                if ($sRun !== 1)
                {
                    foreach ($aJson['result']['list'] as $sKey => $aVal) {
                        $aProduct['result']['list'][] = $aVal;
                    }
                } else
                {
                    $aProduct = $aJson;
                }
            }

            if ($aProduct)
            {
                LibDir::CreateDir(pathinfo($sProduct, PATHINFO_DIRNAME));
                file_put_contents($sProduct, json_encode($aProduct));
            }
        }

        // model
        $aPicture = [];
        $oBasic = new BaseDb(mvc::$cfg['DB']['ZHIPEIC']);
        if (is_file($sProduct))
        {
            $aJson = json_decode(file_get_contents($sProduct), true);
            if (!isset($aJson['result']['list']))
            {
                $aReturn['data'] = '产品列表下载异常';
                return $aReturn;
            }

            // 采集车型列表
            for ($sRun = 0; $sRun < 3; $sRun ++)
            {
                foreach ($aJson['result']['list'] as $sKey => $aVal)
                {
                    $sModel = sprintf('%s/model/%d.json', $sStorge, $aVal['PartItemId']);
                    if (is_file($sModel)) {
                        continue;
                    }

                    if (is_null($this->oClient))
                    {
                        $sResult = $this->cookies($aOption['user'], $aOption['pass']);
                        if (!$sResult)
                        {
                            $aReturn['data'] = '账号登录失败';
                            return $aReturn;
                        }
                    }

                    // 产品详细信息
                    $sGetPartItem = sprintf('%s/GetPartItem/%d.json', $sStorge, $aVal['PartItemId']);
                    if (!is_file($sGetPartItem))
                    {
                        try
                        {
                            $oGuzzle = $this->oClient->post('/factory/PartItemEditor/GetPartItem', [
                                'cookies' => $this->oCookie,
                                'form_params' => [
                                    'PartItemId' => $aVal['PartItemId'],
                                    'NeedErrorDetect' => 0,
                                ],
                            ]);
                            if (200 == $oGuzzle->getStatusCode())
                            {
                                $sGuzzle = $oGuzzle->getBody()->getContents();
                                $aGuzzle = json_decode($sGuzzle, true);
                                if (isset($aGuzzle['message']) && ($aGuzzle['message'] == '执行成功'))
                                {
                                    LibDir::CreateDir(pathinfo($sGetPartItem, PATHINFO_DIRNAME));
                                    file_put_contents($sGetPartItem, $sGuzzle);
                                }
                            }
                        } catch (\GuzzleHttp\Exception\TransferException $oTransfer) {}
                        $this->forSleep();
                    }

                    // 获得车型信息
                    $aValue = json_decode(file_get_contents($sGetPartItem), true);
                    if ($aValue['result']['managedOems'])
                    {
                        $aBuild = [
                            'categoryId' => $aVal['CategoryId'],
                            'autoBrandId' => 0,
                            'managedOems' => $aValue['result']['managedOems']
                        ];
                    } else
                    {
                        $aBuild = [
                            'categoryId' => $aVal['CategoryId'],
                            'autoBrandId' => 0,
                            'relateOems' => $aValue['result']['relateAutoOems'],
                        ];
                    }

                    switch ($aVal['IsNewAutoModel'])
                    {
                        case 2:
                            try
                            {
                                $oGuzzle = $this->oFactory->post('/japi/web_factorymanage/automodelselect/queryadaptationautomodellist', [
                                    'cookies' => $this->oCookie,
                                    'body' => json_encode([
                                        "pageNo" => 1,
                                        "pageSize" => 1000,
                                        "totalCount" => 0,
                                        "autoHierarchyId" => "",
                                        "autoId" => "",
                                        "categoryId" => $aVal['CategoryId'],
                                        "oemId" => "",
                                        "parameterIds" => [],
                                        "partItemId" => $aVal['PartItemId'],
                                        "partItemTempId" => 0
                                    ]),
                                ]);

                                if (200 == $oGuzzle->getStatusCode())
                                {
                                    $sGuzzle = $oGuzzle->getBody()->getContents();
                                    $aGuzzle = json_decode($sGuzzle, true);
                                    if (isset($aGuzzle['message']) && ($aGuzzle['message'] == '执行成功'))
                                    {
                                        LibDir::CreateDir(pathinfo($sModel, PATHINFO_DIRNAME));
                                        file_put_contents($sModel, $sGuzzle);
                                    }
                                }
                            } catch (\GuzzleHttp\Exception\TransferException $oTransfer) {}
                            break;

                        default:
                            try
                            {
                                $oGuzzle = $this->oClient->post('/factory/PartItemEditor/GetOemAutoModelList', [
                                    'cookies' => $this->oCookie,
                                    'form_params' => $aBuild,
                                ]);
                                if (200 == $oGuzzle->getStatusCode())
                                {
                                    $sGuzzle = $oGuzzle->getBody()->getContents();
                                    $aGuzzle = json_decode($sGuzzle, true);
                                    if (isset($aGuzzle['message']) && ($aGuzzle['message'] == '执行成功'))
                                    {
                                        LibDir::CreateDir(pathinfo($sModel, PATHINFO_DIRNAME));
                                        file_put_contents($sModel, $sGuzzle);
                                    }
                                }
                            } catch (\GuzzleHttp\Exception\TransferException $oTransfer) {}
                            break;
                    }

                }
            }

            // 写入数据库
            $aValue = [];
            $aModel = [];
            $oBasic->Del('auto_product', sprintf('and pro_user = "%s"', $aOption['user']));
            $oBasic->Del('auto_product_model', sprintf('and mod_pro_user = "%s"', $aOption['user']));
            foreach ($aJson['result']['list'] as $sKey => $aVal)
            {
                $sModel = sprintf('%s/model/%d.json', $sStorge, $aVal['PartItemId']);
                $sGetPartItem = sprintf('%s/GetPartItem/%d.json', $sStorge, $aVal['PartItemId']);
                if (!is_file($sModel) || !is_file($sGetPartItem)) {
                    continue;
                }

                $aOem = [];
                $sItem = 0;
                $aData = json_decode(file_get_contents($sModel), true);
                $aItem = json_decode(file_get_contents($sGetPartItem), true);

                if ($aItem['result']['managedOems'])
                {
                    $aOem = array_column($aItem['result']['managedOems'], 'displayNo', 'oemId');

                    // 车型信息
                    $sItem = 1;
                }
                if ($aVal['IsNewAutoModel'] == 2) {
                    $sItem = 2;
                }

                switch ($sItem)
                {
                    case 1:
                        foreach ($aData['result']['oem_autoModels'] as $sKKK => $aVVV)
                        {
                            foreach ($aVVV['autoModelSubList'] as $sKK1 => $aVV1)
                            {
                                if (false !== in_array($aVV1['AutoModelSubId'], $aItem['result']['autoBlackList'])) {
                                    continue;
                                }

                                $aModel[] = [
                                    'mod_pro_id' => $aItem['result']['partItemId'],
                                    'mod_pro_user' => $aOption['user'],
                                    'mod_oem' => $aOem[$aVVV['oemId']],
                                    'mod_auo_sub_id' => $aVV1['AutoModelSubId'],
                                    'mod_auo_param' => json_encode($aVV1['AutoModelParamList']),
                                    'model_auto_brand' => $aVV1['AutoBrandName'],
                                    'model_auto_series' => $aVV1['AutoModelName'],
                                    'model_auto_model' => $aVV1['AutoModelSubName'],
                                    'model_json' => '[]',
                                ];
                            }
                        }
                        break;

                    case 2:
                        $aDataAr = [
                            'autoBrandValues' => '品牌',
                            'autoSeriesValue' => '车系',
                            'autoGroupValues' => '车组',
                            'partItemEndTime' => '结束年月',
                            'partItemStartTime' => '开始年月',
                            'tips' => '工信部型号',
                            'remark' => '备注',
                        ];
                        foreach ($aData['result']['detailsList'] as $item)
                        {
                            $aDetail = [];
                            foreach ($aDataAr as $sData_key => $sData_val)
                            {
                                if (!isset($item[$sData_key])) {
                                    continue;
                                }

                                if (is_array($item[$sData_key]))
                                {
                                    $aDetail[] = array_merge($item[$sData_key], [
                                        'autoParameterTypeName' => $sData_val
                                    ]);
                                } else
                                {
                                    $aDetail[] = [
                                        'autoParameterValue' => $item[$sData_key],
                                        'autoParameterTypeName' => $sData_val
                                    ];
                                }
                            }

                            foreach ($aData['result']['dynamicParamColumnList'] as $param_val)
                            {
                                if (!isset($item['partParameterMap'][$param_val['autoParameterTypeId']])) {
                                    continue;
                                }

                                $aDetail[] = array_merge($item['partParameterMap'][$param_val['autoParameterTypeId']], [
                                    'autoParameterTypeName' => $param_val['autoParameterTypeName'],
                                ]);
                            }

                            $aModel[] = [
                                'mod_pro_id' => $aItem['result']['partItemId'],
                                'mod_pro_user' => $aOption['user'],
                                'mod_oem' => '',
                                'mod_auo_sub_id' => 0,
                                'mod_auo_param' => '[]',
                                'model_auto_brand' => '',
                                'model_auto_series' => '',
                                'model_auto_model' => '',
                                'model_json' => json_encode($aDetail),
                            ];
                        }
                        break;

                    default:
                        // 车型信息
                        foreach ($aData['result']['relateAutoOem_autoModels'] as $sKKK => $aVVV)
                        {
                            $aModel[] = [
                                'mod_oem' => '',
                                'mod_pro_id' => $aItem['result']['partItemId'],
                                'mod_pro_user' => $aOption['user'],
                                'mod_auo_sub_id' => $aVVV['autoModelSubId'],
                                'mod_auo_param' => json_encode($aVVV['autoParamList']),
                                'model_auto_brand' => '',
                                'model_auto_series' => '',
                                'model_auto_model' => '',
                                'model_json' => '[]',
                            ];
                        }
                        break;
                }

                // 提取参数
                $aParam = [];
                if ($aItem['result']['fixedProperties'])
                {
                    foreach ($aItem['result']['fixedProperties'] as $sKKK => $aVVV)
                    {
                        if (!$aVVV['Values'] && $aVVV['ParamValueName']) {
                            $aParam[$aVVV['ParamTypeName']] = $aVVV['ParamValueName'];
                        }
                    }
                }

                $sImage = [];
                if ($aItem['result']['itemImages'])
                {
                    foreach ($aItem['result']['itemImages'] as $sKKK => $aVVV)
                    {
                        $sImage[] = $aVVV['origPathUrl'];

                        $sHost = parse_url($aVVV['origPathUrl'], PHP_URL_HOST);
                        $sPath = sprintf('%s/%s/%s',
                            mvc::$cfg['ZHIPEI']['picture'],
                            str_replace(['part-item-images.', '.aliyuncs.com'], '', $sHost),
                            parse_url($aVVV['origPathUrl'], PHP_URL_PATH)
                        );

                        if (is_file($sPath) || isset($aPicture[$sHost][$sPath] )) {
                            continue;
                        }

                        $aPicture[$sHost][$sPath] = [
                            'build' => $aVVV['origPathUrl'], 'method' => 'get', 'param' => [], 'storage' => $sPath
                        ];
                    }
                }

                // 产品信息
                $aValue[$aItem['result']['partItemId']] = [
                    'pro_id' => $aItem['result']['partItemId'],
                    'pro_user' => $aOption['user'],
                    'pro_part' => $aItem['result']['categoryId'],
                    'pro_name' => $aItem['result']['categoryName'],
                    'pro_format' => $aItem['result']['partsNo'],
                    'pro_alias' => $aItem['result']['aliasCodes'],
                    'pro_oems' => json_encode($aOem),
                    'pro_param' => json_encode($aParam),
                    'pro_image' => json_encode($sImage),
                    'pro_unmanaged' => isset($aItem['result']['unmanagedOems'])
                        ? implode('; ', array_column($aItem['result']['unmanagedOems'], 'oemNo'))
                        : ''
                ];

                if (count($aValue) >= 999)
                {
                    $oBasic->addAny('auto_product', array_keys(current($aValue)), $aValue); $aValue = [];
                }
                if (isset($aModel[999])) {
                    $oBasic->addAny('auto_product_model', array_keys($aModel[0]), $aModel); $aModel = [];
                }
            }
            if ($aValue) {
                $oBasic->addAny('auto_product', array_keys(current($aValue)), $aValue); $aValue = [];
            }
            if ($aModel) {
                $oBasic->addAny('auto_product_model', array_keys($aModel[0]), $aModel); $aModel = [];
            }
        } else
        {
            $aReturn['data'] = '产品列表下载失败';
            return $aReturn;
        }

        // 下载图片
        if ($aPicture)
        {
            foreach ($aPicture as $sClient => $aTable)
            {
                $oClient = new Client([
                    'debug' => false,
                    'timeout' => 30,
                    'base_uri' => sprintf('https://%s', $sClient)
                ]);

                sort($aTable);
                $aOption = ['rule' => [], 'thead' => 100];
                $this->guzzle($oClient, $aTable, $aOption);
            }
        }

        return ['status' => true, 'data' => '采集完成'];
    }

    /**
     * 多线程采集
     */
    public function guzzle(\GuzzleHttp\Client $oClient, array $aTable, array $aOption = [])
    {
        if (!$aTable) {
            return false;
        }

        $aRequest = function ($aValue) use ($oClient)
        {
            foreach ($aValue as $sKey => $aVal)
            {
                switch (strtolower($aVal['method']))
                {
                    case 'get':
                        (yield function () use($aVal, $oClient) {
                            return $oClient->getAsync($aVal['build'], isset($aVal['param']) ? $aVal['param'] : []);
                        });
                        break;

                    case 'post':
                        (yield function () use($aVal, $oClient) {
                            return $oClient->postAsync($aVal['build'], isset($aVal['param']) ? $aVal['param'] : []);
                        });
                        break;
                }
            }
        };

        $oPool = new \GuzzleHttp\Pool($oClient, $aRequest($aTable), [
            'concurrency' => isset($aOption['thead']) ? $aOption['thead'] : 3,
            'fulfilled' => function ($oResponse, $sKeyIn) use($aTable, $aOption)
            {
                if (200 == $oResponse->getStatusCode())
                {
                    $aCheck = [];
                    $sContent = $oResponse->getBody()->getContents();
                    if (isset($aOption['rule']) && $aOption['rule'])
                    {
                        foreach ($aOption['rule'] as $sItem => $aItem)
                        {
                            $aCheck[$sItem] = false;
                            switch ($aItem['rule'])
                            {
                                case 'isset':
                                    if (false !== strpos($sContent, $aItem['ruleStr'])) {
                                        $aCheck[$sItem] = true;
                                    }
                                    break;

                                case 'unset':
                                    if (false === strpos($sContent, $aItem['ruleStr'])) {
                                        $aCheck[$sItem] = true;
                                    }
                                    break;

                                case 'isJson':
                                    $aContent = json_decode($sContent, true);
                                    if (is_array($aContent)) {
                                        $aCheck[$sItem] = true;
                                    }
                                    break;

                                case 'json':
                                    $aContent = json_decode($sContent, true);
                                    if (is_array($aContent) && ($aContent[$aItem['ruleStr']['key']] == $aItem['ruleStr']['val'])) {
                                        $aCheck[$sItem] = true;
                                    }
                                    break;
                            }
                        }
                    }

                    $sCheck = true;
                    if (isset($aOption['rule'])) {
                        $sCheck = ($aCheck === array_filter($aCheck)) ? true : false;
                    }

                    if ($sCheck)
                    {
                        LibDir::CreateDir(pathinfo($aTable[$sKeyIn]['storage'], PATHINFO_DIRNAME));
                        file_put_contents($aTable[$sKeyIn]['storage'], $sContent);
                    }
                }

                if (isset($aOption['debug']) && $aOption['debug']) {
                }
            },
            'rejected' => function ($oReason, $sKeyIn) {
            },
        ]);
        $oPool->promise()->wait();
        return true;
    }
}