<?php
namespace Base\Service;

use Base\Model\PromoteModel;
use Base\Model\ApplyModel;
use Base\Tool\Base62;
use Base\Tool\PlistDemo;

class GameSourceService {

    const IS_FIXED_IOS13 = true;
    const DEBUG = true;

    public function __construct()
    {

    }

    /**
     * 获取IPA中的.app后缀目录
     */
    public function getIpaAppPath($zip)
    {
        $appPath = '';
        for ($i = 0; $i < $zip->numFiles; $i++) {
            $name = $zip->getNameIndex($i);
            if (preg_match("/^Payload.*?\.app/", $name, $matches)) {
                $appPath = $matches[0];
                break;
            }
        }
        return $appPath;
    }

    public function deleteOldChannelConfigFolder($zip, $txChannelFolder)
    {
        for ($i = 0; $i < $zip->numFiles; $i++) {
            $name = $zip->getNameIndex($i);
            if (strpos($name, $txChannelFolder) === 0) {
                $zip->deleteName($name);
            }
        }
    }
    
    public function getChannelConfigFile($zip, $sdkVersion)
    {
        $configUrl = '';
        if ($sdkVersion == 1) {
            $configUrl = "META-INF/mch.properties";
        } else {
            $appPath = $this->getIpaAppPath($zip);
            $configUrl = $appPath . '/_CodeSignature/TXChannel';
        }
        return $configUrl;
    }

    public function getChannelConfigFolder($zip, array $packData)
    {
        $appPath = $this->getIpaAppPath($zip);
        return $appPath . '/TXChannel/' . Base62::encode(json_encode($packData, JSON_UNESCAPED_UNICODE));
    }

    public function getGameSourceUrl($gameSource)
    {
        if (empty($gameSource)) {
            return '';
        }
        $path = '';
        if($gameSource['file_type'] == 1) {
            $path = './Uploads/SourcePack/';
        }else{
            $path = './Uploads/Ios/original/';
        }
        $fileUrl = $path . $gameSource['file_name'];
        return ROOTTT . ltrim($fileUrl, './');
    }
    
    public function packChannel($localPath, $game, $gameSource, $apply = null)
    {
        $packData = [
            'game_id' => $game['id'],
            'game_name' => $game['game_name'],
            'game_appid' => $game['game_appid'],
            'promote_id' => $apply ? $apply['promote_id'] : '0',
            'promote_account' => $apply ? $apply['promote_account'] : '自然渠道',
            'source_version' => $gameSource['source_version'],
        ];

        $zip = new \ZipArchive();
        if (!$zip->open($localPath, \ZipArchive::CREATE)) {
            return false;
        }

        if (self::IS_FIXED_IOS13 && $game['sdk_version'] == 2) {
            $channelFolder = $this->getChannelConfigFolder($zip, $packData);
            return $this->packChannelFolder($zip, $channelFolder);
        } else {
            $channelFile = $this->getChannelConfigFile($zip, $game['sdk_version']);
            return $this->packChannelFile($zip, $channelFile, $packData);
        }

        $zip->close();

        return false;
    }

    /**
     * 打入渠道信息文件
     * @param   string  $zip        包文件
     * @param   string  $distFile   打入文件名
     * @param   array   $packData   打入信息
     * @return  boolean 是否成功
     */
    public function packChannelFile($zip, $distFile, array $packData)
    {
        $zip->addFromString($distFile, json_encode($packData));
        return true;
    }

    /**
     * 打入渠道信息目录(用于IOS,主要为了解决IOS13问题)
     * @param   string  $zip            包文件
     * @param   string  $distFolder     打入文件夹
     * @return  boolean 是否成功
     */
    public function packChannelFolder($zip, $distFolder)
    {
            $rows = explode('/' , $distFolder);
            unset($rows[count($rows) -1]);
            $txChannelFolder = implode('/', $rows) . '/';
            $this->deleteOldChannelConfigFolder($zip, $txChannelFolder);
            $zip->addEmptyDir($distFolder);
            return true;
    }

    /**
     * 原包打包
     */
    public function sourcePack($gameSource, $game)
    {
        $relativeUrl = $gameSource['file_url'];
        $localPath = ROOTTT . ltrim($relativeUrl, './');

        $originalUrl = '';
        if ($game['sdk_version'] == 2) {
            $oldLocalPath = $localPath;
            $localPath = str_replace('Uploads/SourcePack', 'Uploads/Ios/original', $oldLocalPath);
            $originalUrl = $relativeUrl;
            $relativeUrl = str_replace('Uploads/SourcePack', 'Uploads/Ios/original', $relativeUrl);
            copy($oldLocalPath, $localPath);
        }
        $status = $this->packChannel($localPath, $game, $gameSource);
        if (!$status) {
            return [
                'status' => false,
                'message' => '打包失败,原包加入信息失败!',
            ];
        }

        $distFilePath = 'SourcePack/' . $gameSource['file_name'];
        $result = $this->uploadPackage($localPath, $distFilePath);
        $fileUrl = '';
        if ($result['status']) {
            $fileUrl = $result['data']['url'];
            $fileUrl = $fileUrl == '@' ? $relativeUrl : $fileUrl;
        } else {
            return [
                'status' => false,
                'message' => '打包失败,上传OSS失败!' . $result['message'],
            ];
        }
        
        $plistUrl = '';
        $orgPlistUrl = '';
        if ($game['sdk_version'] == 2) {
            $params = [
                'packageName' => $gameSource['bao_name'],
                'gameId' => $game['id'],
                'gameName' => $game['game_name'],
                'promoteId' => 0,
                'packageUrl' => $fileUrl,
                'gameIcon' => get_cover($game['icon'], 'path'),
                'type' => 'pack'
            ];
            
            $result = $this->createPlist($params);
            if ($result['status']) {
                $plistUrl = $result['data']['path'];
            } else {
                return [
                    'status' => false,
                    'message' => '打包失败,生成plist文件失败!' . $result['message'],
                ];
            }

            $params['type'] = 'org';
            $result = $this->createPlist($params);
            if ($result['status']) {
                $orgPlistUrl = $result['data']['path'];
            } else {
                return [
                    'status' => false,
                    'message' => '打包失败,生成原包plist文件失败!' . $result['message'],
                ];
            }
        }
        return [
            'status' => true,
            'message' => '打包成功!',
            'data' => [
                'plistUrl' => $plistUrl,
                'orgPlistUrl' => $orgPlistUrl,
                'fileUrl' => $fileUrl,
                'originalUrl' => $originalUrl,
            ]
        ];
    }

    /**
     * 渠道打包
     */
    public function channelPack($gameSource, $game, $apply, $launchCount = 0)
    {
        $debugTime1 = microtime(true);

        $gameSourceUrl = $this->getGameSourceUrl($gameSource);
        if ($gameSource == null  || !file_exists($gameSourceUrl)) {
            M('apply', 'tab_')->where(['id' => $apply['id']])->setField('enable_status', -1);
        }

        /* 检测是否存在投放申请,存在则更改投放申请信息,否则进行渠道打包 */
        if ($launchCount > 0) {
            M('apply', 'tab_')->where(['id' => $apply['id']])->setField('enable_status', 3);
            $launchData = ['launch_packge' => 2, 'launch_down_url'=>'' , 'launch_plist_url'=>''];
            M('apply_launch', 'tab_')->where(['apply_id' => $apply['id'], 'launch_packge'=>['in', [0, 2, 3]]])->save($launchData);
        }

        $savePath = '';
        $fileName = 'game_package' . $apply['game_id'] . '-' . $apply['promote_id'];
        if ($apply['sdk_version'] == 1) {
            $fileName .= '.apk';
            $savePath = 'Uploads/GamePack/' . $fileName;
        } else {
            $fileName .= '.ipa';
            $savePath = 'Uploads/IosGamePack/' . $fileName;
        }
        $relativePath = './' . $savePath;
        $localPath = ROOTTT . $savePath;

        $debugTime2 = microtime(true);

        copy($gameSourceUrl, $localPath);

        $debugTime3 = microtime(true);

        $status = $this->packChannel($localPath, $game, $gameSource, $apply);
        if (!$status) {
            return [
                'status' => false,
                'message' => '打包失败,加入渠道信息失败!',
            ];
        }

        $debugTime4 = microtime(true);

        $distFilePath = 'GamePack/' . $fileName;
        $result = $this->uploadPackage($localPath, $distFilePath, true);
        if ($result['status']) {
            $packageUrl = $result['data']['url'];
            $packageUrl = $packageUrl == '@' ? $relativePath : $packageUrl;
        } else {
            return [
                'status' => false,
                'message' => '打包失败,上传OSS失败!' . $result['message'],
            ];
        }

        $debugTime5 = microtime(true);

        $plistInfo = ['game_id' => $apply['game_id'], 'promote_id' => $apply['promote_id']];
        $plistUrl = '';
        if ($apply['sdk_version'] == 2) {
            $params = [
                'packageName' => $gameSource['bao_name'],
                'gameId' => $game['id'],
                'gameName' => $game['game_name'],
                'promoteId' => $apply['promote_id'],
                'packageUrl' => $packageUrl,
                'gameIcon' => get_cover($game['icon'], 'path'),
                'type' => 'pack'
            ];
            $result = $this->createPlist($params);
            if ($result['status']) {
                $plistUrl = $result['data']['path'];
            } else {
                return [
                    'status' => false,
                    'message' => '打包失败,生成plist文件失败!' . $result['message'],
                ];
            }
        }
        $applyService = new ApplyService();
        $applyService->updateAfterPack($apply, $packageUrl, $plistUrl);

        $debugTime6 = microtime(true);
        $debugInfo = '';
        if (self::DEBUG) {
            $debugInfo .= '[' . 
                '总计:' . ($debugTime6 - $debugTime1) . 
                ' 复制:' . ($debugTime3 - $debugTime2) . 
                ' 打包:' . ($debugTime4 - $debugTime3) . 
                ' 上传:' . ($debugTime5 - $debugTime4) . 
            ']';
        }

        return [
            'status' => true,
            'message' => '打包成功!' . $debugInfo,
            'data' => [
                'plistUrl' => $plistUrl,
            ]
        ];
    }

    public function uploadPackage($localFilePath, $distFilePath, $isDeleteLocal = false, $isChunk = false)
    {
        if (get_tool_status('oss_storage') == 1) {
            if ($isChunk) {
                return $this->uploadPackageChunk($localFilePath, $distFilePath, $isDeleteLocal);
            } else {
                return $this->uploadPackageOnce($localFilePath, $distFilePath, $isDeleteLocal);
            }
        } else {
            // 不上传OSS等第三方服务器
            return [
                'status' => true,
                'message' => '上传成功',
                'data' => [
                    'url' => '@'
                ],
            ];
        }
    }
    public function uploadPackageChunk($localFilePath, $distFilePath, $isDeleteLocal = false)
    {
        $client = new Client([
            'base_uri' => C('UPLOAD_SERVER_URL'),
            'timeout'  => 10.0,
        ]);
        $response = $client->post('/upload', [
            'verify' => false,
            'form_params' => [
                'file' => $gameId,
                'dist' => $distFilePath,
                'is_delete_local' => 0,
            ]
        ]);
        $result = (string)$response->getBody();
        $result = json_decode($result, true);
        if (!$result) {
            return [
                'status' => false,
                'message' => '请求打包失败',
            ];
        }
        return $result;
    }

    public function uploadPackageOnce($localFilePath, $distFilePath, $isDeleteLocal = false)
    {
        $ossService = new OssService();
        $result = $ossService->upload($localFilePath, $distFilePath);
        if ($isDeleteLocal && file_exists($localFilePath)) {
            @unlink($localFilePath);
        }
        return $result;
    }

    //生成游戏渠道plist文件
    public function createPlist($params)
    {
        $packageName = $params['packageName'] ?? '';
        $gameName = $params['gameName'] ?? '';
        $gameId = $params['gameId'] ?? 0;
        $promoteId = $params['promoteId'] ?? 0;
        $packageUrl = $params['packageUrl'] ?? '';
        $platformId = $params['platformId'] ?? 0;
        $position = $params['position'] ?? 0;
        $gameIcon = $params['gameIcon'] ?? '';
        $type = $params['type'] ?? '';

        if ($gameId == 0) {
            return [
                'status' => false,
                'message' => '游戏ID错误',
            ];
        }
        if ($type == '' || !in_array($type, ['org', 'pack'])) {
            return [
                'status' => false,
                'message' => '类型错误',
            ];
        }

        $xml = new \DOMDocument();
        $xml->loadXML(PlistDemo::$content);
        $online = $xml->getElementsByTagName('dict');   //查找节点
        $elements = $online->item(1)->getElementsByTagName('string');   //第二个节点下所有string
        foreach ($elements as $element) {
            switch ($element->textContent) {
                case 'ipa_url':
                    if (preg_match("/http/", $packageUrl)) {
                        $element->nodeValue = $packageUrl;
                    } else {
                        $element->nodeValue = C('DOMAIN_DOWNLOAD') . ltrim($packageUrl, '.');
                    }
                    break;
                case 'icon':
                    if (preg_match("/http/", $gameIcon)) {
                        $element->nodeValue = $gameIcon;
                    } else {
                        $element->nodeValue = C('DOMAIN_OFFICIAL_PC') . ltrim($gameIcon, '.');
                    }
                    break;
                case 'com.dell':
                    $element->nodeValue = $packageName;
                    break;
                case '1.0.0':
                    $element->nodeValue = false;
                    break;
                case 'mchdemo':
                    $element->nodeValue = $gameName;
                    break;
            }
        }

        $fileName = '';
        if ($type == 'pack') {
            if ($promoteId == 0) {
                $fileName = 'Uploads/SourcePlist/'. $gameId . '.Plist';
            } elseif ($platformId > 0) {
                $fileName = 'Uploads/GamePlist/'. $gameId . '-' . $promoteId . '-' . $platformId . '-' .$position . '.Plist';
            } else {
                $fileName = 'Uploads/GamePlist/'. $gameId . '-' . $promoteId . '.Plist';
            }
        } elseif ($type == 'org') {
            $fileName = 'Uploads/OrgSourcePlist/'. $gameId . '.Plist';
        }
        $xml->save('./' . $fileName);
        return [
            'status' => true,
            'message' => '生成成功',
            'data' => [
                'path' => './' . $fileName
            ]
        ];
    }
}