<?php
declare (strict_types = 1);

namespace app\command;

use think\console\Command;
use think\console\Input;
use think\console\input\Argument;
use think\console\input\Option;
use think\console\Output;
use think\facade\Db;

class DataMigration extends Command
{
    protected $println;
    private function println($msg) {
        ($this->println)($msg);
    }

    protected function configure()
    {
        // 指令配置
        $this->setName('migrate')
            ->setDescription('执行数据迁移');
    }

    protected function execute(Input $input, Output $output)
    {
        // 指令输出
        $this->println = function ($msg) use ($output) {
            $output->writeln($msg);   
        };

        // 迁移tock产品分类
        // $this->productTcoCategory();

        // 迁移产品分类
        // $this->productCategory();

        // 迁移文章
        // $this->migrateArticle([
        //     1 => 2,
        //     2 => 3,
        //     33 => 4,
        //     36 => 5,
        //     16 => 7,
        //     31 => 8,
        //     32 => 9
        // ]);

        // 迁移faq
        // $this->migrateFaq();

        $output->writeln('success');
    }

    // 迁移tco产品分类
    private function productTcoCategory()
    {
        $category = Db::connect('old')
            ->name('product_tco_category')
            ->select();

        foreach ($category as $val) {
            $item = [
                'id'          => $val['id'],
                'language_id' => $val['country_code'] == 'ZH' ? 1 : 2,
                'name'        => $val['name'],
                'tco_id'      => $val['tco_id'],
                'tco_pid'     => $val['tco_pid'],
                'tco_path'    => $val['tco_path'],
                'erp_id'      => $val['erp_id'],
                'erp_pid'     => $val['erp_pid'],
                'erp_path'    => $val['erp_path'],
                'erp_code'    => $val['erp_code'],
                'disabled'    => $val['disabled'],
                'sync_time'   => $val['sync_time'],
            ];
            Db::name('product_tco_category')->insert($item);
        }
    }

    // 迁移产品分类
    private function productCategory()
    {
        $tco_category = Db::connect('old')
            ->name('product_tco_category')
            ->select();
        $tco_category_map = [];
        foreach ($tco_category as $val) {
            $key = sprintf("%s_%s", $val['category_id'], $val['country_code']);
            if (isset($tco_category_map[$key])) {
                $tco_category_map[$key] = [];
            }
            $tco_category_map[$key][] = $val['id'];
        }

        $category = Db::connect('old')
            ->name('product_category')
            ->select()
            ->toArray();

        // 处理数据
        $this->handlerProductCategory(array_to_tree($category, 0, 'pid', 1), $tco_category_map);
    }
    private function handlerProductCategory($category, $map) {
        foreach ($category as $val) {
            $key = sprintf("%s_%s", $val['id'], $val['country_code']);
            $item = [
                'id'                   => $val['id'],
                'language_id'          => $val['country_code'] == 'ZH' ? 1 : 2,
                'unique_id'            => uniqid('PRO_CATE_'),
                'pid'                  => $val['pid'],
                'name'                 => $val['name'],
                'icon'                 => $val['icon'],
                'desc'                 => $val['description'],
                'related_tco_category' => isset($map[$key]) ? implode(',', $map[$key]) : '',
                'sort'                 => $val['sort'] == 9999 ? 0 : $val['sort'],
                'level'                => $val['level'],
                'is_show'              => $val['isshow'],
            ];
            Db::name('product_category')->insert($item);
            if (isset($val['children'])) {
                $this->handlerProductCategory($val['children'], $map);
            }
        }
    }

    // 迁移文章
    private function migrateArticle($category_map = [])
    {
        $this->println('开始迁移文章......');

        if (empty($category_map)) {
            throw new \Exception('请确认分类ID');
        }

        $article = Db::connect('old')
            ->name('article')
            ->where('cid', 'in', array_keys($category_map))
            ->order(['id' => 'asc'])
            ->cursor();

        $uploadMgr = new UploadMannager();
        foreach ($article as $v) {
            // 处理封面图片
            $image = '';
            $ret = $uploadMgr->upload($uploadMgr->download($v['picture']), 'image');
            if ($ret['code'] == 0) {
                $image = $ret['data']['path'];
            } else {
                $image = $ret['msg'];
            }

            // 处理详情中图片
            $content = $v['content'];
            preg_match_all('/<img.*?src=[\'"](.*?)[\'"].*?>/i', $content, $matches);
            $content_images = [];
            foreach ($matches[1] as $val) {
                try {
                    $ret = $uploadMgr->upload($uploadMgr->download($val), 'image');
                    if ($ret['code'] == 0) {
                        $content_images[$val] = $ret['data']['path'];
                    }
                } catch (\Throwable $th) {
                    continue;
                }
            }
            foreach ($content_images as $key => $val) {
                $content = str_replace($key, $val, $content);
            }
            $item = [
                'language_id'  => $v['country_code'] == 'ZH' ? 1 : 2,
                'category_id'  => $category_map[$v['cid']],
                'title'        => $v['name'],
                'author'       => $v['writer'],
                'source'       => $v['source'],
                'image'        => $image,
                'desc'         => $v['description'],
                'recommend'    => $v['recommend'],
                'sort'         => $v['sort'] == 9999 ? 0 : $v['sort'],
                'link'         => $v['jump_link'],
                'content'      => $content,
                'view_count'   => $v['viewcount'],
                'praise_count' => $v['zancount'],
                'seo_title'    => $v['seo_title'],
                'seo_keywords' => $v['seo_keyword'],
                'seo_desc'     => $v['seo_description'],
                'enabled'      => $v['stat'],
                'release_time' => date('Y-m-d H:i:s', $v['createtime'])
            ];
            Db::name('article')->insert($item);

            $this->println('迁移文章ID：' . $v['id']);
        }
    }

    // 迁移FAQ
    private function migrateFaq()
    {
        $faq = Db::connect('old')
            ->name('fq')
            ->where('id', '>=', 10)
            ->where('stat', '>=', 0)
            ->select();

        $uploadMgr = new UploadMannager();
        foreach ($faq as $key => $val) {
            $image = '';
            $ret = $uploadMgr->upload($uploadMgr->download($val['picture']), 'image');
            if ($ret['code'] == 0) {
                $image = $ret['data']['path'];
            } else {
                $image = $ret['msg'];
            }
            $content = explode("\n", $val['content']);
            $content = '<p>' . implode("</p><p>", $content) . '</p>';
            $item = [
                'language_id' => $val['country_code'] == 'ZH' ? 1 : 2,
                'image'       => $image,
                'question'    => $val['name'],
                'answer'      => $content,
                'recommend'   => $val['is_home'],
                'sort'        => $val['sort'] == 9999 ? 0 : $val['sort']
            ];
            Db::name('faq')->insert($item);
        }
    }
}

class UploadMannager
{
    const   UPLOAD_BASE_API    = 'http://dev.ow.f2b211.com';
    const   DOWNLOAD_BASE_API  = 'https://www.orico.com.cn';
    const   DOWNLOAD_TEMP_PATH = '/var/www/html/orico-official-website/public/migrate_temp_images';
    private $username          = 'admin';
    private $password          = 'Aa-1221';
    private $token             = '';
    private $retrys            = [];

    public function __construct()
    {
        // 登录获取token
        $this->token = $this->getAuthorization();
    }

    // 下载图片
    public function download($file_name)
    {
        if (empty($file_name)) {
            return '';
        }
        $url = $file_name;
        if (\think\helper\Str::startsWith($file_name, 'http')) {
            $need = 'orico.com.cn';
            if (!\think\helper\Str::contains($file_name, $need)) {
                return $url;
            }
            $url = self::DOWNLOAD_BASE_API . \think\helper\Str::substr($file_name, mb_strpos($file_name, $need) + mb_strlen($need));
        } else {
            $url = self::DOWNLOAD_BASE_API . str_replace(" ", "%20", $file_name);
        }
        
        $file_path = self::DOWNLOAD_TEMP_PATH . $file_name;
        $opts = [
            'http' => [
                'method' => 'GET',
                'header' => 'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64)'
            ]
        ];
        $context = stream_context_create($opts);
        $file    = file_get_contents($url, false, $context);
        $dir     = dirname($file_path);
        if (!is_dir($dir)) {
            mkdir($dir, 0777, true);
        }
        file_put_contents($file_path, $file, FILE_USE_INCLUDE_PATH);
        return $file_path;
    }

    // 上传图片
    public function upload($file_path, $field_name) {
        if (empty($file_path)) {
            return ['code' => 0, 'msg' => 'file_path为空', 'data' => ['path' => '']];
        }
        $ch        = curl_init(self::UPLOAD_BASE_API . '/admapi/v1/images/faq/upload');
        $post_data = [
            $field_name => new \CURLFile($file_path)
        ];
        curl_setopt($ch, CURLOPT_HTTPHEADER, [
            'Authorization: Bearer ' . $this->token
        ]);
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        $response = curl_exec($ch);
        $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);

        // 登录失效
        if ($http_code == 401) {
            $this->token = $this->getAuthorization();
            if (!isset($this->retrys[$file_path])) {
                $this->retrys[$file_path] = 0;
            }
            if ($this->retrys[$file_path] > 0) {
                throw new \Exception('[' . $file_path . ']上传重试失败');
            }
            $this->retrys[$file_path] += 1;
            return $this->upload($file_path, $field_name);
        }

        return json_decode($response, true);
    }

    // 登录获取token
    private function getAuthorization()
    {
        $ch = curl_init(self::UPLOAD_BASE_API . '/admapi/v1/user/login');
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, [
            'username' => $this->username,
            'password' => md5($this->password)
        ]);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        $response = curl_exec($ch);
        $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);

        if ($http_code != 200) {
            throw new \Exception('获取token失败');
        }

        $result = json_decode($response, true);
        if ($result['code'] != 0) {
            throw new \Exception($result['msg']);
        } 

        return $result['data']['token'];
    }
}
