<?php

namespace model\pro;

use \model;

class picTpl extends model
{
    public $table = 'pro_pic_tpl';
    private $operationDir = null;
    public function __construct()
    {
        parent::__construct();
    }

    /**
     * @method 获取模板列表(分页)
     * @author hongzhang
     * @copyright 2026-02-10
     */
    public function getList($params)
    {
        $filters = $params['filters'];
        $page = $params['page'];
        $pagesize = $params['rows'];
        $sidx = empty($params['sidx']) ? 'ptl_id' : $params['sidx'];
        $sord = empty($params['sord']) ? 'desc' : $params['sord'];
        $orderby = $params['orderby'];

        $join = ["[>]pro_brand" => ["ptl_pb_id" => "pb_id"]];

        $where = $this->filter2medoo($filters, function (&$field, &$op, &$data) {
            if ($field == 'pb_name') {
                $field = 'ptl_pb_id';
            }
        });
       
        if(!\p::isAdmin() && $params['pwcode']){
            $proBrands = \p::areas($params['pwcode']);
    		$where['AND #rule_brand'] = ['ptl_pb_id'=>explode(',',$proBrands)];
       	}
        $where = $this->listWhere($where, $page, $pagesize, $sidx, $sord, $orderby);
        if ($page > 0 && $pagesize > 0) {
            $fields = '*';
            $pages = $this->paging($this->table, $join, $fields, $where, $page, $pagesize);
            $where["LIMIT"] = [$pages['limit'], $pagesize];
        }
        $fields = ['ptl_id', 'ptl_name', 'ptl_lang', 'pb_' . LG_NAME . '(pb_name)', 'ptl_opuser', 'ptl_update_time', 'ptl_create_time', 'ptl_cfg'];
        $row = $this->db->select($this->table, $join, $fields, $where);
        foreach($row as &$item){
            $item['captions']['ptl_lang'] = \mvc::$cfg['LANGS'][$item['ptl_lang']]['name'];
        }
        
        $data = [
            'page' => $page,
            'total' => $pages['total'],
            'records' => $pages['records'],
            'rows' => $row
        ];
        return $data;
    }

    /**
     * @method 获取模板列表(简要)
     * @author hongzhang
     * @copyright 2026-02-10
     */
    public function getListSimple()
    {

        $join = ["[>]pro_brand" => ["ptl_pb_id" => "pb_id"]];
        $fields = ['ptl_id', 'ptl_name', 'pb_' . LG_NAME . '(pb_name)', 'ptl_opuser', 'ptl_update_time', 'ptl_create_time', 'ptl_cfg'];
        $row = $this->db->select($this->table, $join, $fields);
        return $row;
    }

    /**
     * @method 新增模板
     * @author hongzhang
     * @copyright 2026-02-10
     */
    public function add($data)
    {
        $exist = $this->db->select($this->table, ['ptl_id'], ['ptl_name' => $data['tplName'],'ptl_pb_id'=>$data['tplBrand']]);
        if($exist){
            return ['status'=>false,'msg'=>'已存在类似的模板，请修改模板名称或品牌名称'];
        }
        $ptlCfg = [];
        if (!empty($data['texts'])) {
            if (isset($data['texts'][0]) && is_array($data['texts'][0])) {
                foreach ($data['texts'] as $textItem) {
                    if (!$textItem) continue;
                    $ptlCfg[] = $textItem;
                }
            } else {
                $ptlCfg[] = $data['texts'];
            }
        }
        if ($data['logo']) {
            $ptlCfg[] = $data['logo'];
        }
        if ($data['watermark']) {
            $ptlCfg[] = $data['watermark'];
        }
        if ($data['qrcode']) {
            $ptlCfg[] = $data['qrcode'];
        }
        if ($data['background']) {
            $ptlCfg[] = $data['background'];
        }
        if ($data['template']) {
            $ptlCfg[] = $data['template'];
        }
        if ($data['testProOInfo']) {
            $ptlCfg[] = $data['testProOInfo'];
        }
        if ($ptlCfg) {
            $ptlCfg = json_encode($ptlCfg, JSON_UNESCAPED_UNICODE);
        }
        $insertData = [
            'ptl_lang' => $data['tplLang'],
            'ptl_name' => $data['tplName'],
            'ptl_pb_id' => $data['tplBrand'],
            'ptl_cfg' => $ptlCfg,
            'ptl_opuser' => getOpuser(),
            'ptl_update_time' => getNowTime(),
            'ptl_create_time' => getNowTime(),
        ];
        $this->db->insert($this->table, $insertData);
        $id = $this->db->id();
        return ['status'=>true,'ptl_id' => $id];
    }

    /**
     * @method 更新模板
     * @author hongzhang
     * @copyright 2026-02-10
     */
    public function update($id, $data)
    {
        $ptlCfg = [];
        if (!empty($data['texts'])) {
            if (isset($data['texts'][0]) && is_array($data['texts'][0])) {
                foreach ($data['texts'] as $textItem) {
                    if (!$textItem) continue;
                    $ptlCfg[] = $textItem;
                }
            } else {
                $ptlCfg[] = $data['texts'];
            }
        }
        if ($data['logo']) {
            $ptlCfg[] = $data['logo'];
        }
        if ($data['watermark']) {
            $ptlCfg[] = $data['watermark'];
        }
        if ($data['qrcode']) {
            $ptlCfg[] = $data['qrcode'];
        }
        if ($data['background']) {
            $ptlCfg[] = $data['background'];
        }
        if ($data['template']) {
            $ptlCfg[] = $data['template'];
        }
        if ($data['testProOInfo']) {
            $ptlCfg[] = $data['testProOInfo'];
        }
        $ptlCfg = json_encode($ptlCfg, JSON_UNESCAPED_UNICODE);
        $updateData = [
            'ptl_lang' => $data['tplLang'],
            'ptl_name' => $data['tplName'],
            'ptl_pb_id' => $data['tplBrand'],
            'ptl_cfg' => $ptlCfg,
            'ptl_opuser' => getOpuser(),
            'ptl_update_time' => getNowTime(),
        ];
        $this->db->update($this->table, $updateData, ['ptl_id' => $id]);
    }

    /**
     * @method 删除模板
     * @author hongzhang
     * @copyright 2026-02-10
     */
    public function del($ids)
    {
        $this->db->delete($this->table, ['ptl_id' => $ids]);
        return [];
    }

    /**
     * @method 获取品牌列表
     * @author hongzhang
     * @copyright 2026-02-10
     */
    public function getProBrandList($pwcode = '')
    {   
        $where = [];
        if($pwcode && !\p::isAdmin()){
            $proBrands = \p::areas($pwcode);
            $where['AND #rule_brand'] = ['pb_id'=>explode(',',$proBrands)];
        }
        $join = [];
        $fields = ['pb_id', 'pb_' . LG_NAME . '(pb_name)'];
        $row = $this->db->select('pro_brand', $join, $fields,$where);
        return $row;
    }

    /**
     * @method 获取模板详情
     * @author hongzhang
     * @copyright 2026-02-10
     */
    public function getTplCfg($ptl_id)
    {
        $fields = ['ptl_id', 'ptl_name', 'ptl_lang', 'ptl_pb_id', 'ptl_cfg'];
        $row = $this->db->select($this->table, [], $fields, ['ptl_id' => $ptl_id]);
        return $row[0] ?? [];
    }

    /**
     * @method 根据图片id获取模板展示所需信息
     * @author hongzhang
     * @copyright 2026-02-11
     */
    public function getTplInfo($pic_fileid, $lang = '')
    {
        if(!$lang){
            $lang = 'cn';
        }
        $langField = \mvc::$cfg['LANGS'][$lang]['field'];
        $table = 'pro_pic';
        $join = [
            "[><]pro(p)" => ["pic_p_id" => "p_id"],
            "[><]files" => ["pic_fileid" => "fileid"],
            "[><]pro_factory" => ["p.p_pf_id" => "pf_id"],
        ];
        $fields = ['p_id', 'filepath', 'filebasename', 'fileextname', 'p_' . $langField . '(p_name)', 'pf_name', 'p_oe', 'p_innum', 'p_model_' . $langField . '(p_model)', 'p_engine', 'p_chassis'];
        $row = $this->db->select($table, $join, $fields, ['pic_fileid' => $pic_fileid]);
        return $row[0] ?? [];
    }

    /**
     * @method 图片绑定模板
     * @author hongzhang
     * @copyright 2026-02-11
     */
    public function bindTpl($p_id, $pic_fileid, $tpl_id)
    {
        $table = 'pro_pic';
        $this->db->update($table, ['pic_ptl_id' => $tpl_id], ['pic_fileid' => $pic_fileid, 'pic_p_id' => $p_id]);
        return [];
    }

    /**
     * @method 根据品牌id随机取一个相关商品信息
     * @author hongzhang
     * @copyright 2026-02-25
     */
    public function getProInfoByBrand($pb_id = 1, $lang = '', $p_id = '', $p_innum = '')
    {
        $table = 'pro';
        if(!$lang){
            $lang = 'cn';
        }
        $langField = \mvc::$cfg['LANGS'][$lang]['field'];
        $join = ['[>]files' => ['p_pic' => 'fileid']];
        $fields = ['p_id', 'p_'.$langField.'(p_name)', 'p_oe', 'p_innum', 'p_model_'.$langField.'(p_model)', 'p_engine', 'p_chassis','filename'];
        $where = [
            'p_pb_id' => $pb_id,
            'LIMIT'   => 1
        ];
        if($p_id){
            $where['p_id'] = $p_id;
        }
        if($p_innum){
            $where['p_innum_format'] = formatNum($p_innum);
        }
        // 获取品牌二维码url信息
        $qrUrl = $this->db->get('pro_brand', ['pb_prourl'], ['pb_id' => $pb_id]);
        $row = $this->db->rand($table, $join, $fields, $where);
        if($row[0]){
            $row[0]['qrUrl'] = $qrUrl['pb_prourl'] ?? '';
        }
        return $row[0] ?? [];
    }

    /**
     * @method 更新模板单元格
     * @author hongzhang
     * @copyright 2026-04-01
     */
    public function updateCell($params)
    {
        $tplid = $params['tplid'];
        $editArr = [];
        if($params['ptl_lang']){
            $editArr['ptl_lang'] = $params['ptl_lang'];
        }
        $this->db->update($this->table, $editArr, ['ptl_id' => $tplid]);
        return [];
    }


    public function getAllTplList()
    {
        $fields = '*';
        $row = $this->db->select($this->table, $fields);
        return $row;
    }

    /**
     * 根据模板ID和图片数据合成新图片
     * @param int $templateId 模板ID
     * @param string $imageData 原始图片数据（可以是路径或base64格式）
     * @param array $additionalData 额外数据（如产品信息等）
     * @return string 合成后图片的路径或base64数据
     */
    public function generateImageWithTemplate($templateId, $imageData, $fileid='')
    {   
        $tmpBase = \mvc::$cfg['dir']['cache'].'/'.date('Y-m');
        $this->operationDir = $tmpBase . '/operation_' . date('Ymd_His') . '_' . uniqid();
        mkdirs($this->operationDir);
        if(!is_dir($this->operationDir))exitJson(0,'临时图片缓存目录创建失败');
        // 判断输入数据类型并处理
        if (preg_match('/^data:image\/(\w+);base64,/', $imageData, $matches)) {
            // 是base64格式，先保存为临时文件
            $imageFormat = $matches[1];
            $imageDataClean = substr($imageData, strpos($imageData, ',') + 1);
            $imageContent = base64_decode($imageDataClean);
            
            if ($imageContent === false) {
                throw new \Exception('base64数据解码失败');
            }
            
            // 生成临时文件
            $tempFilePath = $this->operationDir . '/input_image.' . $imageFormat;
            file_put_contents($tempFilePath, $imageContent);
            $imagePath = $tempFilePath;
        } else {
            // 是文件路径
            $imagePath = $imageData;
        }

        try {
            // 获取模板配置
            $templateConfig = $this->getTplCfg($templateId);
            if (empty($templateConfig)) {
                throw new \Exception('模板不存在');
            }

            // 解析模板配置
            $tplCfg = json_decode($templateConfig['ptl_cfg'], true);
            if (json_last_error() !== JSON_ERROR_NONE) {
                throw new \Exception('模板配置解析失败');
            }

            // 验证图片文件是否存在
            if (!file_exists($imagePath)) {
                throw new \Exception('原图片文件不存在');
            }

            // 模板语言信息
            $tplLang = $templateConfig['ptl_lang'] ?? 'cn';

            // 获取图片信息
            $imageInfo = getimagesize($imagePath);
            if (!$imageInfo) {
                throw new \Exception('无效的图片文件');
            }

            $templateImage = $this->createImageResource($imagePath, $imageInfo[2]);
            if (!$templateImage) {
                throw new \Exception('无法创建图片资源');
            }
            $canvasWidth = 800;
            $canvasHeight = 600;
            $targetImage = imagecreatetruecolor($canvasWidth, $canvasHeight);
            imagealphablending($targetImage, true);
            imagesavealpha($targetImage, true);
            $additionalData = [];
            if($fileid){
                $picTpl =  new picTpl();
                $additionalData = $picTpl->getTplInfo($fileid, $tplLang);

            }

            $backgroundConfig = ['mode' => 'none', 'color' => '#ffffff', 'layer' => 0];
            $templateConfigValue = ['width' => 0, 'height' => 0, 'layer' => 10];
            $renderElements = [];
            foreach ($tplCfg as $element) {
                if (!is_array($element) || empty($element['type'])) {
                    continue;
                }
                if ($element['type'] === 'background') {
                    $backgroundConfig = array_merge($backgroundConfig, $element);
                    continue;
                }
                if ($element['type'] === 'template') {
                    if (isset($element['width']) && is_numeric($element['width'])) {
                        $templateConfigValue['width'] = (float)$element['width'];
                    }
                    if (isset($element['height']) && is_numeric($element['height'])) {
                        $templateConfigValue['height'] = (float)$element['height'];
                    }
                    if (isset($element['layer']) && is_numeric($element['layer'])) {
                        $templateConfigValue['layer'] = (int)$element['layer'];
                    }
                    continue;
                }
                $renderElements[] = $element;
            }
            $drawQueue = [
                ['type' => 'background', 'layer' => $this->normalizeLayerValue($backgroundConfig['layer'] ?? 0), 'order' => 0, 'config' => $backgroundConfig],
                ['type' => 'template', 'layer' => $this->normalizeLayerValue($templateConfigValue['layer'] ?? 10), 'order' => 1, 'config' => $templateConfigValue]
            ];
            foreach ($renderElements as $element) {
                $type = $element['type'];
                $order = 10;
                $defaultLayer = 20;
                switch ($type) {
                    case 'text':
                        $order = 2;
                        $defaultLayer = 20;
                        break;
                    case 'logo':
                        $order = 3;
                        $defaultLayer = 30;
                        break;
                    case 'watermark':
                        $order = 4;
                        $defaultLayer = 40;
                        break;
                    case 'qrcode':
                        $order = 5;
                        $defaultLayer = 50;
                        break;
                    default:
                        continue 2;
                }
                $drawQueue[] = [
                    'type' => $type,
                    'layer' => $this->normalizeLayerValue($element['layer'] ?? $defaultLayer),
                    'order' => $order,
                    'config' => $element
                ];
            }
            usort($drawQueue, function ($a, $b) {
                if ($a['layer'] === $b['layer']) {
                    return $a['order'] - $b['order'];
                }
                return $a['layer'] - $b['layer'];
            });
            foreach ($drawQueue as $item) {
                switch ($item['type']) {
                    case 'background':
                        $this->fillCanvasBackground($targetImage, $item['config'], $canvasWidth, $canvasHeight);
                        break;
                    case 'template':
                        $this->drawTemplateImage($targetImage, $templateImage, $canvasWidth, $canvasHeight, $item['config']);
                        break;
                    case 'text':
                        $this->addTextToImage($targetImage, $item['config'], $additionalData);
                        break;
                    case 'logo':
                        $this->addLogoToImage($targetImage, $item['config']);
                        break;
                    case 'watermark':
                        $this->addWatermarkToImage($targetImage, $item['config']);
                        break;
                    case 'qrcode':
                        $this->addQrCodeToImage($targetImage, $item['config'], $additionalData);
                        break;
                }
            }

            $fileExtension = image_type_to_extension($imageInfo[2], false);
            $fileName = 'generated_' . $templateId . '_' . time() . '_' . uniqid() . '.' . $fileExtension;
            $outputPath = $this->operationDir . $fileName;

            // 保存合成后的图片
            $result = $this->saveImage($targetImage, $outputPath, $imageInfo[2]);

            // 释放资源
            imagedestroy($templateImage);
            imagedestroy($targetImage);

            if (!$result) {
                throw new \Exception('图片保存失败');
            }
            $base64Result = $this->imageToBase64($outputPath);
        
            return $base64Result;
        } finally {
            // 清理整个操作目录（如果有的话）
            if (isset($this->operationDir) && is_dir($this->operationDir)) {
                $this->removeDirectory($this->operationDir);
            }
        }
    }

    /**
     * 将图片文件转换为base64格式
     * @param string $imagePath 图片路径
     * @return string base64格式的图片数据
     */
    public function imageToBase64($imagePath)
    {
        if (!file_exists($imagePath) && !filter_var($imagePath, FILTER_VALIDATE_URL)) {
            throw new \Exception('图片文件不存在');
        }

        $imageInfo = getimagesize($imagePath);
        if (!$imageInfo) {
            throw new \Exception('无效的图片文件');
        }

        $imageData = file_get_contents($imagePath);
        if ($imageData === false) {
            throw new \Exception('无法读取图片文件');
        }

        $mimeType = image_type_to_mime_type($imageInfo[2]);
        $base64Data = base64_encode($imageData);

        return 'data:' . $mimeType . ';base64,' . $base64Data;
    }

    /**
     * 创建图片资源
     * @param string $imagePath 图片路径
     * @param int $imageType 图片类型
     * @return resource|false 图片资源
     */
    private function createImageResource($imagePath, $imageType)
    {
        switch ($imageType) {
            case IMAGETYPE_JPEG:
            case IMAGETYPE_JPEG2000:
                return imagecreatefromjpeg($imagePath);
            case IMAGETYPE_PNG:
                $image = imagecreatefrompng($imagePath);
                // 保留透明度
                imagealphablending($image, false);
                imagesavealpha($image, true);
                return $image;
            case IMAGETYPE_GIF:
                return imagecreatefromgif($imagePath);
            case IMAGETYPE_WEBP:
                if (function_exists('imagecreatefromwebp')) {
                    $image = imagecreatefromwebp($imagePath);
                    imagealphablending($image, false);
                    imagesavealpha($image, true);
                    return $image;
                } else {
                    throw new \Exception('服务器不支持WebP格式');
                }
            default:
                return false;
        }
    }

    private function fillCanvasBackground($image, $backgroundConfig, $canvasWidth, $canvasHeight)
    {
        $mode = $backgroundConfig['mode'] ?? 'none';
        if (!in_array($mode, ['none', 'color', 'image'], true)) {
            $mode = 'none';
        }
        $colorHex = $backgroundConfig['color'] ?? '#ffffff';
        $rgbColor = $this->hexToRgb($colorHex);
        $bgColor = imagecolorallocate($image, $rgbColor['r'], $rgbColor['g'], $rgbColor['b']);
        if ($mode === 'none') {
            $white = imagecolorallocate($image, 255, 255, 255);
            imagefilledrectangle($image, 0, 0, $canvasWidth, $canvasHeight, $white);
            return;
        }
        imagefilledrectangle($image, 0, 0, $canvasWidth, $canvasHeight, $bgColor);
        if ($mode !== 'image') {
            return;
        }
        $bgVal = $backgroundConfig['val'] ?? '';
        if (!$bgVal) {
            return;
        }
        $bgPath = \mvc::$cfg['dir']['files'].'/pictpl/bg/'.$bgVal;
        if (!file_exists($bgPath)) {
            return;
        }
        $bgInfo = getimagesize($bgPath);
        if (!$bgInfo) {
            return;
        }
        $bgImage = $this->createImageResource($bgPath, $bgInfo[2]);
        if (!$bgImage) {
            return;
        }
        $sw = imagesx($bgImage);
        $sh = imagesy($bgImage);
        if (!$sw || !$sh) {
            imagedestroy($bgImage);
            return;
        }
        $scale = max($canvasWidth / $sw, $canvasHeight / $sh);
        $dw = (int)round($sw * $scale);
        $dh = (int)round($sh * $scale);
        $dx = (int)round(($canvasWidth - $dw) / 2);
        $dy = (int)round(($canvasHeight - $dh) / 2);
        imagecopyresampled($image, $bgImage, $dx, $dy, 0, 0, $dw, $dh, $sw, $sh);
        imagedestroy($bgImage);
    }

    private function normalizeLayerValue($layer)
    {
        $n = (int)$layer;
        if ($n < 0) {
            $n = 0;
        }
        if ($n > 99) {
            $n = 99;
        }
        return $n;
    }

    private function drawTemplateImage($canvas, $templateImage, $canvasWidth, $canvasHeight, $templateConfigValue = [])
    {
        $sw = imagesx($templateImage);
        $sh = imagesy($templateImage);
        if (!$sw || !$sh) {
            return;
        }
        $width = 0;
        if (is_array($templateConfigValue) && isset($templateConfigValue['width']) && is_numeric($templateConfigValue['width'])) {
            $width = (float)$templateConfigValue['width'];
        }
        if ($width <= 0) {
            $baseScale = min($canvasWidth / $sw, $canvasHeight / $sh);
            $width = $sw * $baseScale;
        }
        $dw = (int)round($width);
        $dh = (int)round(($dw * $sh) / $sw);
        $dx = (int)round(($canvasWidth - $dw) / 2);
        $dy = (int)round(($canvasHeight - $dh) / 2);
        imagecopyresampled($canvas, $templateImage, $dx, $dy, 0, 0, $dw, $dh, $sw, $sh);
    }

    /**
     * 添加文本到图片
     * @param resource $image 图片资源
     * @param array $textConfig 文本配置
     * @param array $additionalData 额外数据
     */
    private function addTextToImage($image, $textConfig, $additionalData)
    {
        $key = $textConfig['key'];
        $text = '';
        switch ($key) {
            case 'p_name':
                $text = $additionalData[$key] ?? '';
                break;
            case 'p_oe':
                $text = ($additionalData['pf_name'] ?? '') . ':' . ($additionalData[$key] ?? '');
                break;
            case 'p_innum':
                $text = '物料编码:' . ($additionalData[$key] ?? '');
                break;
            case "p_model":
                $text = "车型:" . ($additionalData[$key] ?? '');
                break;
            case "p_engine":
                $text = "发动机:" . ($additionalData[$key] ?? '');
                break;
            case "p_chassis":
                $text = "底盘:" . ($additionalData[$key] ?? '');
                break;
    
        }
        $customLabelRaw = $textConfig['label'] ?? ($textConfig['prefixLabel'] ?? '');
        $customLabel = $this->decodeEdgeSpaceLabel($customLabelRaw);
        if ($customLabel !== '') {
            $text = $customLabel . $text;
        }
         // 确保文本是UTF-8编码
        $text = mb_convert_encoding($text, 'UTF-8', 'auto');
        $fontSize = $textConfig['fontSize'] ?? 12;
        $color = $textConfig['color'] ?? '#000000';
        $x = $textConfig['x'] ?? 10;
        $y = $textConfig['y'] ?? 10;
        $bold = $textConfig['bold'] ?? false; // 是否加粗
        $fontFile = \mvc::$cfg['dir']['project'] . '/model/qrcode/zhttfs/simhei.ttf'; // 黑体
        // 转换颜色
        $rgbColor = $this->hexToRgb($color);
        $textColor = imagecolorallocate($image, $rgbColor['r'], $rgbColor['g'], $rgbColor['b']);

        // 使用默认字体
        imagettftext($image, $fontSize, 0, $x, $y + $fontSize, $textColor, $fontFile, $text);
        
    }

    private function decodeEdgeSpaceLabel($value)
    {
        $label = (string)$value;
        $edgeSpaceToken = mb_chr(0xE000, 'UTF-8');
        $label = str_replace([$edgeSpaceToken, '__QG_EDGE_SPACE__', '\uE000'], ' ', $label);
        // 兜底处理残留私有区字符
        return preg_replace('/\x{E000}/u', ' ', $label);
    }

    /**
     * 添加Logo到图片
     * @param resource $image 图片资源
     * @param array $logoConfig Logo配置
     */
    private function addLogoToImage($image, $logoConfig)
    {   
        if($logoConfig['type']=='watermark'){
            $logoPath = \mvc::$cfg['dir']['files'].'/pictpl/watermark/'.$logoConfig['val'];
        }else{
            $logoPath = \mvc::$cfg['dir']['files'].'/pictpl/logo/'.$logoConfig['val'];
        }
        if (!file_exists($logoPath)) {
            return;
        }

        $logoInfo = getimagesize($logoPath);
        $logoImage = $this->createImageResource($logoPath, $logoInfo[2]);

        if (!$logoImage) {
            return;
        }
        $x = $logoConfig['x'] ?? 10;
        $y = $logoConfig['y'] ?? 10;
        $sw = $logoInfo[0];
        $sh = $logoInfo[1];
        $width = isset($logoConfig['width']) && is_numeric($logoConfig['width']) ? (float)$logoConfig['width'] : 0;
        if ($width <= 0) {
            $width = $sw;
        }
        $height = isset($logoConfig['height']) && is_numeric($logoConfig['height']) ? (float)$logoConfig['height'] : 0;
        if ($height <= 0) {
            $height = ($width * $sh) / $sw;
        }
        $width = (int)round($width);
        $height = (int)round($height);
        // 调整Logo尺寸
        $resizedLogo = imagecreatetruecolor($width, $height);
        imagealphablending($resizedLogo, false);
        imagesavealpha($resizedLogo, true);
        $transparent = imagecolorallocatealpha($resizedLogo, 255, 255, 255, 127);
        imagefilledrectangle($resizedLogo, 0, 0, $width, $height, $transparent);

        imagecopyresampled($resizedLogo, $logoImage, 0, 0, 0, 0, $width, $height, $sw, $sh);

        // 合成到主图
        imagecopy($image, $resizedLogo, $x, $y, 0, 0, $width, $height);

        // 释放资源
        imagedestroy($logoImage);
        imagedestroy($resizedLogo);
    }

    /**
     * 添加水印到图片
     * @param resource $image 图片资源
     * @param array $watermarkConfig 水印配置
     */
    private function addWatermarkToImage($image, $watermarkConfig)
    {
        // 水印通常与Logo处理方式类似，可以根据具体需求调整
        $this->addLogoToImage($image, $watermarkConfig);
    }

    /**
     * 添加二维码到图片
     * @param resource $image 图片资源
     * @param array $qrConfig 二维码配置
     * @param array $additionalData 额外数据
     */
    private function addQrCodeToImage($image, $qrConfig, $additionalData)
    {
        // 优先使用模板中配置的二维码链接；为空时回退到原逻辑
        $qrText = trim((string)($qrConfig['val'] ?? ''));
        if ($qrText !== '') {
            $pInnum = (string)($additionalData['p_innum'] ?? '');
            $encodedInnum = rawurlencode($pInnum);
            // 支持 url={物料编码}、{物料编码} 及其URL编码占位
            $qrText = str_replace(
                ['url={物料编码}', 'url=%7B物料编码%7D', '{物料编码}', '%7B物料编码%7D'],
                ['url=' . $encodedInnum, 'url=' . $encodedInnum, $pInnum, $encodedInnum],
                $qrText
            );
        } elseif (!empty($additionalData['p_id'])) {
            $qrText = \mvc::$cfg['urls']['homeh5'] . '/item/info?id=' . $additionalData['p_id'] . '&type=pro';
        }

        if (empty($qrText)) {
            return;
        }

        // 创建临时文件存储二维码
        $qrTempFile = $this->operationDir . '/qr_temp_' . uniqid() . '.png';
        
        try {
            // 生成二维码 - 先生成原始尺寸
            \QRcode::png($qrText, $qrTempFile);
            
            if (!file_exists($qrTempFile)) {
                return;
            }

            // 加载二维码图片
            $qrImage = $this->createImageResource($qrTempFile, IMAGETYPE_PNG);

            if (!$qrImage) {
                return;
            }

            // 获取原始二维码尺寸
            $originalWidth = imagesx($qrImage);
            $originalHeight = imagesy($qrImage);
            
            // 获取期望的尺寸
            $targetSize = (int)($qrConfig['size'] ?? 80); // 默认80px
            if ($targetSize <= 0) {
                $targetSize = 80;
            }
            $x = $qrConfig['x'] ?? 10;
            $y = $qrConfig['y'] ?? 10;

            // 创建指定尺寸的新二维码图像
            $resizedQrImage = imagecreatetruecolor($targetSize, $targetSize);
            imagealphablending($resizedQrImage, false);
            imagesavealpha($resizedQrImage, true);
            $transparent = imagecolorallocatealpha($resizedQrImage, 255, 255, 255, 127);
            imagefilledrectangle($resizedQrImage, 0, 0, $targetSize, $targetSize, $transparent);

            // 将原始二维码缩放到指定尺寸
            imagecopyresampled(
                $resizedQrImage, $qrImage,
                0, 0, 0, 0,           // 目标x,y,源x,y
                $targetSize, $targetSize, // 目标宽高
                $originalWidth, $originalHeight // 源宽高
            );

            // 合成到主图
            imagecopy($image, $resizedQrImage, $x, $y, 0, 0, $targetSize, $targetSize);

            // 释放资源
            imagedestroy($qrImage);
            imagedestroy($resizedQrImage);
        } catch (\Exception $e) {
            // 记录错误但不中断程序执行
            error_log("二维码生成失败: " . $e->getMessage());
        }
    }

    /**
     * 保存图片
     * @param resource $image 图片资源
     * @param string $path 保存路径
     * @param int $imageType 图片类型
     * @return bool 是否保存成功
     */
    private function saveImage($image, $path, $imageType)
    {
        switch ($imageType) {
            case IMAGETYPE_JPEG:
            case IMAGETYPE_JPEG2000:
                return imagejpeg($image, $path, 90);
            case IMAGETYPE_PNG:
                return imagepng($image, $path);
            case IMAGETYPE_GIF:
                return imagegif($image, $path);
            case IMAGETYPE_WEBP:
                if (function_exists('imagewebp')) {
                    return imagewebp($image, $path, 90);
                } else {
                    // 如果不支持WebP，保存为JPEG
                    $jpegPath = preg_replace('/\.webp$/', '.jpg', $path);
                    return imagejpeg($image, $jpegPath, 90);
                }
            default:
                return imagejpeg($image, $path, 90);
        }
    }

    /**
     * 十六进制颜色转RGB
     * @param string $hexColor 十六进制颜色
     * @return array RGB数组
     */
    private function hexToRgb($hexColor)
    {
        $hexColor = ltrim($hexColor, '#');
        $length = strlen($hexColor);
        $rgb = [];

        if ($length == 3) {
            $rgb['r'] = hexdec(str_repeat(substr($hexColor, 0, 1), 2));
            $rgb['g'] = hexdec(str_repeat(substr($hexColor, 1, 1), 2));
            $rgb['b'] = hexdec(str_repeat(substr($hexColor, 2, 1), 2));
        } elseif ($length == 6) {
            $rgb['r'] = hexdec(substr($hexColor, 0, 2));
            $rgb['g'] = hexdec(substr($hexColor, 2, 2));
            $rgb['b'] = hexdec(substr($hexColor, 4, 2));
        } else {
            $rgb['r'] = 0;
            $rgb['g'] = 0;
            $rgb['b'] = 0;
        }

        return $rgb;
    }

    /**
     * 递归删除目录及其内容
     * @param string $dir 目录路径
     * @return bool
     */
    private function removeDirectory($dir) {
        if (!is_dir($dir)) {
            return false;
        }
        
        $files = array_diff(scandir($dir), array('.', '..'));
        foreach ($files as $file) {
            $filePath = $dir . DIRECTORY_SEPARATOR . $file;
            if (is_dir($filePath)) {
                $this->removeDirectory($filePath);
            } else {
                unlink($filePath);
            }
        }
        return rmdir($dir);
    }
}
