<?php
/**
 * Created by PhpStorm.
 * User: Zero
 * Date: 2020/7/27
 * Time: 11:44
 */

namespace Meibuyu\Micro\Tools;

use Exception;
use Hyperf\Contract\ConfigInterface;
use PhpOffice\PhpSpreadsheet\Worksheet\Drawing;
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;

class Drawer
{

    /**
     * @var ConfigInterface
     */
    protected $config;

    private $rootPath;

    private $savePath = '';

    private $ossDomain = 'http://huaperfect-file-service.oss-cn-hangzhou.aliyuncs.com';

    public function __construct()
    {
        $this->config = container(ConfigInterface::class);
        $this->rootPath = $this->config->get('server.settings.document_root', BASE_PATH . '/public');
    }

    private function parseImagePath($imagePath)
    {
        if (strstr($imagePath, 'http') !== false) {
            $imagePath = $this->downloadWebImage($imagePath);
        }
        return $imagePath;
    }

    /**
     * 下载网络图片
     * @param string $url
     * @param string $path
     * @return string
     */
    public function downloadWebImage($url, $path = null)
    {
        $url = $this->parseUrl($url);
        // excel画图中下载图片时对图片名做urlencode处理,防止中文名不能正常画图片的bug
        $pathinfo = pathinfo($url);
        $filename = trim($pathinfo['filename']);
        $ext = strtolower($pathinfo['extension']);
        $filename = "$filename.$ext";
        $savePath = $this->parseSavePath($pathinfo['dirname'], $path);
        if (!is_dir($savePath)) {
            // 判断路径是否存在,不存在,则创建
            mkdir($savePath, 0777, true);
        }
        $filePath = $savePath . '/' . $filename;
        if (!file_exists($filePath)) {
            $ch = curl_init();
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // 信任任何证书
            curl_setopt($ch, CURLOPT_URL, $url);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
            curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 30);
            $file = curl_exec($ch);
            curl_close($ch);
            $resource = fopen($filePath, 'a');
            fwrite($resource, $file);
            fclose($resource);
        }
        return $filePath;
    }

    private function parseUrl($url)
    {
        if (!preg_match('/%[0-9A-Z]{2}/', $url)) {
            $url = rawurlencode($url);
            $url = str_replace("%3A", ":", $url);
            $url = str_replace("%2F", "/", $url);
            $url = str_replace("%3F", "?", $url);
            $url = str_replace("%3D", "=", $url);
            $url = str_replace("%26", "&", $url);
        }
        return $this->handleOssUrl($url);
    }

    /**
     * 处理保存路径
     * @param $dirname
     * @param $path
     * @return string
     * @author Zero
     */
    private function parseSavePath($dirname, $path)
    {
        $path = trim($path, '/');
        $path = $this->rootPath . '/download/images/' . ($path ?: $this->savePath) . '/';
        if (strstr($dirname, $this->ossDomain) !== false) {
            // 以oss的原路径为保存路径
            $dirname = str_replace($this->ossDomain, '', $dirname);
            $dirname = trim($dirname, '/');
            $path = $path . $dirname . '/';
        }
        return $path;
    }

    // 替换阿里云图片内部地址
    private function handleOssUrl($url)
    {
        if ($this->config->get('app_env') !== 'dev') {
            $url = str_replace('oss-cn-hangzhou.aliyuncs.com', 'oss-accelerate.aliyuncs.com', $url);
            $this->ossDomain = 'http://huaperfect-file-service.oss-accelerate.aliyuncs.com';
        }
        return $url;
    }

    /**
     * description:下载文件到服务端 增加判断是否是webp 格式的图片处理
     * author: fuyunnan
     * @param string $url
     * @param string $path 文件路径
     * @return string
     * @throws
     * Date: 2020/11/20
     */
    public function downLoadImgWebpChannel($url, $path = '')
    {
        $originUrl = $url;
        //如果shopify 去掉版本号
        if (strpos($url, 'shopify') !== false) {
            $url = substr($url, 0, strpos($url, '?v='));
        }
        $savePath = $this->rootPath . '/download/images/' . ($path ? $path . '/' : $this->savePath);
        create_file_dir($savePath);
        $filePath = $this->toWebpImg($url, $savePath);
        if (!file_exists($filePath)) {
            $filename = trim(pathinfo($url, PATHINFO_FILENAME));
            $ext = strtolower(pathinfo($url, PATHINFO_EXTENSION));
            $filePath = $savePath . "$filename.$ext";
            $ch = curl_init();
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // 信任任何证书
            curl_setopt($ch, CURLOPT_URL, $originUrl);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
            curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 30);
            $file = curl_exec($ch);
            curl_close($ch);
            $resource = fopen($filePath, 'a');
            fwrite($resource, $file);
            fclose($resource);
            $filePath = $this->toWebpImg($filePath, $savePath);
        }
        return $filePath;
    }

    /**
     * description:将图像绘到excel表格上
     * author: fuyunnan
     * @param string $url 图片地址
     * @param string $childPath 图片地址 用sku名作为文件夹名称
     * @param int $h 图片高度
     * @param string $p 单元格索引
     * @param Worksheet $sheet
     * @return void
     * @throws
     * Date: 2020/11/23
     */
    public function drawImgExcel($url, $childPath, $h, $p, $sheet)
    {
        try {
            //下载图片到本地
            $absPath = $this->downLoadImgWebpChannel($url, $childPath);
            $drawing = new Drawing();
            $drawing->setPath($absPath)
                ->setCoordinates($p)
                ->setHeight($h)
                ->setOffsetX(1)
                ->setOffsetY(1)
                ->setWorksheet($sheet);
        } catch (Exception $e) {
            put_log($e->getMessage(), 'draw2Excel.log');
        }
    }

    /**
     * description:检查文件是否是webp格式的文件
     * 如果是,转化为jpeg格式的文件,并且返回文件的绝对地址.
     * author: fuyunnan
     * @param string $filePath 文件的绝对地址
     * @param string $savePath 文件重新保存的地址
     * @return string
     * @throws
     * Date: 2020/11/23
     */
    private function toWebpImg($filePath, $savePath)
    {
        $filename = trim(pathinfo($filePath, PATHINFO_FILENAME));
        $ext = strtolower(pathinfo($filePath, PATHINFO_EXTENSION));
        $imgInfo = '';

        //如果存在直接返回 防止每次获取文件资源
        if (file_exists($savePath . "$filename.$ext")) {
            return $savePath . "$filename.$ext";
        }
        $filePath && $imgInfo = getimagesize($filePath);
        if ($imgInfo && end($imgInfo) == "image/webp") {
            $filename = trim(pathinfo($filePath, PATHINFO_FILENAME));
            $im = imagecreatefromwebp($filePath); // 加载 WebP 文件
            switch ($ext) {
                case 'jpg':
                    $toNewFileName = $savePath . $filename . '.jpg';
                    break;
                case 'png':
                    $toNewFileName = $savePath . $filename . '.png';
                    break;
                case 'jpeg':
                    $toNewFileName = $savePath . $filename . '.jpeg';
                    break;
                default:
                    $toNewFileName = $savePath . $filename . '.jpeg';
                    break;
            }
            imagejpeg($im, $toNewFileName, 30);//转化图片比例
            imagedestroy($im);
            return $toNewFileName;
        }
        return $savePath . "$filename.$ext";
    }

    /**
     * @param $imgPath
     * @param int $px
     * @return bool|string
     * @throws Exception
     */
    public function addBoard($imgPath, $px = 2)
    {
        $imgPath = $this->parseImagePath($imgPath);

        $imgPathInfo = pathinfo($imgPath);
        $filename = $imgPathInfo['filename']; // 图片名称
        $ext = $this->getImgExt($imgPath);

        [$img_w, $img_h] = getimagesize($imgPath); // 图片大小

        $savePath = $this->rootPath . '/download/board/' . $this->savePath;
        if (!is_dir($savePath)) {
            // 判断路径是否存在,不存在,则创建
            mkdir($savePath, 0777, true);
        }
        $imgNewPath = $savePath . '/' . $filename . '.' . $ext;
        if (file_exists($imgNewPath)) {
            return $imgNewPath;
        }

        switch ($ext) {
            case 'jpeg':
            case 'jpg':
                $img_create_func = 'imagecreatefromjpeg';
                $img_save_func = 'imagejpeg';
                break;
            case 'png':
                $img_create_func = 'imagecreatefrompng';
                $img_save_func = 'imagepng';
                break;
            case 'bmp':
                $img_create_func = 'imagecreatefrombmp';
                $img_save_func = 'imagebmp';
                break;
            case 'gif':
                $img_create_func = 'imagecreatefromgif';
                $img_save_func = 'imagegif';
                break;
            case 'vnd.wap.wbmp':
                $img_create_func = 'imagecreatefromwbmp';
                $img_save_func = 'imagewbmp';
                break;
            case 'xbm':
                $img_create_func = 'imagecreatefromxbm';
                $img_save_func = 'imagexbm';
                break;
            default:
                throw new Exception("图片类型不支持");
        }

        // 黑色背景图片
        $im = @imagecreatetruecolor(($img_w + $px), ($img_h + $px)) or die ("Cannot Initialize new GD image stream");
        // 为真彩色画布创建背景,再设置为透明
        $color = imagecolorallocate($im, 0, 0, 0);
        imagefill($im, 0, 0, $color);
        imageColorTransparent($im, $color);
        // 把图片放到黑色背景图片上。边框是1px
        $resource = $img_create_func($imgPath);
        imagecopy($im, $resource, $px / 2, $px / 2, 0, 0, $img_w, $img_h);

        $res = $img_save_func($im, $imgNewPath);

        imagedestroy($im);
        return $res ? $imgNewPath : false;
    }

    /**
     * 拼图
     * @param $imgPathList
     * @param string $name
     * @return bool|string
     */
    public function mergeImages($imgPathList, $name = '')
    {
        $maxW = $maxH = 0;
        $filenameList = [];
        $imageList = [];
        foreach ($imgPathList as $k => $path) {
            $path = $this->parseImagePath($path);
            $imgPathInfo = pathinfo($path);
            $filename = $imgPathInfo['filename']; // 图片名称
            $ext = $imgPathInfo['extension']; // 图片扩展名
            [$w, $h] = getimagesize($path); // 图片大小
            $imageList[$k] = [
                'path' => $path,
                'filename' => $filename,
                'ext' => $ext,
                'w' => $w,
                'h' => $h,
            ];
            $filenameList[] = $filename;
            $maxW += $w;
            if ($maxH < $h) {
                $maxH = $h;
            }
        }
        $filenameList = collect($filenameList)->unique()->sort()->toArray();
        $filename = implode('_', $filenameList);
        $savePath = $this->rootPath . '/download/merge/' . $this->savePath;
        if (!is_dir($savePath)) {
            // 判断路径是否存在,不存在,则创建
            mkdir($savePath, 0777, true);
        }
        $imgNewPath = $savePath . '/' . ($name ?: $filename) . '.png';
        if (file_exists($imgNewPath)) {
            return $imgNewPath;
        }
        // 黑色背景图片
        $im = @imagecreatetruecolor($maxW, $maxH) or die ("Cannot Initialize new GD image stream");
        // 为真彩色画布创建背景,再设置为透明
        $color = imagecolorallocate($im, 0, 0, 0);
        imagefill($im, 0, 0, $color);
        imageColorTransparent($im, $color);
        // 循环画图片
        $dstX = 0;
        foreach ($imageList as $item) {
            $resource = imagecreatefromstring(file_get_contents($item['path']));
            imagecopy($im, $resource, $dstX, 0, 0, 0, $item['w'], $item['h']);
            $dstX += $item['w'];
        }
        $res = imagepng($im, $imgNewPath);
        imagedestroy($im);
        return $res ? $imgNewPath : false;
    }

    /**
     * 画图片
     * @param string $path 图片路径
     * @param int $h 图片高度
     * @param string $p 单元格索引
     * @param Worksheet $sheet
     * @param int $boardPx
     */
    public function draw2Excel($path, $h, $p, $sheet, $boardPx = 0)
    {
        try {
            $path = $this->parseImagePath($path);
            if ($boardPx) {
                $path = $this->addBoard($path, $boardPx);
            }
            $drawing = new Drawing();
            $drawing->setPath($path)->setCoordinates($p)->setHeight($h)->setOffsetX(1)->setOffsetY(1)->setWorksheet($sheet);
        } catch (Exception $e) {
            put_log($e->getMessage(), 'draw2Excel.log');
        }
    }

    public function setSavePath($path)
    {
        $this->savePath = trim($path, '/');
    }

    /**
     * 获取图片扩展名
     * @param $path
     * @return bool|mixed|string
     * @author Zero
     */
    public function getImgExt($path)
    {
        $ext = false;
        $info = getimagesize($path);
        if (isset($info['mime']) && $info['mime']) {
            $ext = explode('/', $info['mime'])[1];
        } else {
            $ext = strtolower(pathinfo($path, PATHINFO_EXTENSION));
            $ext = explode('?', $ext)[0] ?? $ext;
        }
        return $ext;
    }

}