<?php 
namespace model;


class aiImage
{   
    private $apiKey; 
    public $baseUrl = 'https://picupapi.tukeli.net/api/v1/';
    public $apiName = '图可丽AI图像接口';
    public function __construct()
    {   
        $this->apiKey = \mvc::$cfg['aiimg']['apikey'];
    }

    /**
     * @param  Array $params  mattingType,crop:是否裁剪,bgcolor:填充背景色,source:文件地址或URL，outputFormat：输出图片格式
     * @method 图可丽抠图接口，支持图片URL和图片文件两种输入方式，自动识别输入类型并调用对应接口进行处理
     * @author zhengweihua 
     * @copyright 2026-03-18
     */
    public function matting($params)
    {       
        if($params['source']==''){
            exitJson(-1,'请提供图片地址或图片文件');
        }
        $source = $params['source'];
        $mattingType = $params['mattingType'] ?: 6;

        // 计算源图片的md5值
        $sourceMd5 = $this->getSourceMd5($source);

        //根据输出格式判断base64附加头png,webp,jpg
        $outputFormat = isset($params['outputFormat']) && $params['outputFormat'] ?: 'png';
        if($outputFormat=='jpg'){
            $base64header = 'data:image/jpeg;base64,';
        }elseif($outputFormat=='webp'){
            $base64header = 'data:image/webp;base64,';
        }else{
            $base64header = 'data:image/png;base64,';
        }

        // 检查是否存在已抠图的缓存文件
        $cacheDir = \mvc::$cfg['dir']['files'].'/ai_matting/'.substr($sourceMd5, 0, 2).'/'.substr($sourceMd5, 2, 2);
        $cacheFile = $cacheDir.'/'.$sourceMd5.'.'.$outputFormat;
        
        // 检查缓存是否存在且有效
        if(file_exists($cacheFile)){
            $cachedContent = file_get_contents($cacheFile);
            if($cachedContent !== false && strlen($cachedContent) > 0){
                // 返回缓存的图片
                return $base64header.base64_encode($cachedContent);
            }
        }
        //如果是url链接
        if(stripos($source,'http')===0){
            $urlPath = 'mattingByUrl';
            $getQuery = [
                'url' => $source,
                'mattingType' => $mattingType
            ];
            $post_arr = [];
            $method = 'GET';
        }else{
            $tmpBase = \mvc::$cfg['dir']['cache'].'/'.date('Y-m');
            $operationDir = $tmpBase . '/' . date('Ymd_His') . '_' . uniqid();
            @mkdir($operationDir, 0777, true);
            // 判断输入数据类型并处理
            if (preg_match('/^data:image\/(\w+);base64,/', $source, $matches)) {
                // 是base64格式，先保存为临时文件
                $imageFormat = $matches[1];
                $imageDataClean = substr($source, strpos($source, ',') + 1);
                $imageContent = base64_decode($imageDataClean);
                
                if ($imageContent === false) {
                    throw new \Exception('base64数据解码失败');
                }
                
                // 生成临时文件
                $tempFilePath = $operationDir . '/input_image.' . $imageFormat;
                file_put_contents($tempFilePath, $imageContent);
                $imagePath = $tempFilePath;
            } else {
                // 是文件路径
                $imagePath = $source;
            }    

            $urlPath = 'matting2';
            $post_arr = [
                'file' => new \CURLFile($imagePath),
                'mattingType' => $mattingType,
                'is_form' => true
            ];
            $getQuery = [
                'mattingType' => $mattingType
            ];
            $method = 'POST';
        }
        //是否裁剪
        if(isset($params['crop'])){
            $getQuery['crop'] = $params['crop']?true:false;
        }
        //背景颜色
        if(isset($params['bgcolor']) && $params['bgcolor']!=''){
            $getQuery['bgcolor'] = $params['bgcolor'];
        }
        //输出图片格式
        if(isset($params['outputFormat']) && $params['outputFormat']!=''){
            $getQuery['outputFormat'] = $params['outputFormat'];
        }
        
        $headers = [
            'APIKEY:' . $this->apiKey
        ];
        $res = $this->Get($urlPath, $getQuery, $post_arr, $headers,$method);
        if($res['code']==0 && $res['data']){
            
            $result = $res['data']['imageBase64'] ? $base64header.$res['data']['imageBase64'] : '';
            
            if($result && $res['data']['imageBase64']){
                // 解码base64内容并保存到缓存
                $imageContent = base64_decode($res['data']['imageBase64']);
                if($imageContent !== false){
                    // 创建缓存目录
                    @mkdir($cacheDir, 0777, true);
                    // 保存抠图结果到缓存
                    file_put_contents($cacheFile, $imageContent);
                }
            }
            
            return $result;
        }else{
            exitJson(0,$this->apiName.'接口异常:' . ($res['msg'] ?? '未知错误'));
        }
    }

    /**
     * @method 统一请求入口：自动识别 GET/POST
     * @param string $urlPath 请求路径
     * @param array $get_arr GET 参数
     * @param array $post_arr POST 数据
     * @param method POST 默认都是 POST，需要GET 请求请自行声明
     * @return mixed
     */
    public function Get($urlPath, $get_arr = [], $post_arr = [],$headers=[], $method = 'POST')
    {   

        try {
            $url = $this->baseUrl . $urlPath;

            // 添加 GET 参数
            if (!empty($get_arr)) {
                $url .= (strpos($url, '?') === false ? '?' : '&') . http_build_query($get_arr);
            }

            $ch = curl_init();

            // 是否是上传文件的请求
            $isFormRequest = isset($post_arr['is_form']) && $post_arr['is_form'];
            $isQuery = isset($post_arr['is_query']) && $post_arr['is_query'];
            // 构建 headers
            $defaultHeaders = [];

            if ($isFormRequest) {
                $defaultHeaders[] = 'Content-Type: multipart/form-data';
            }elseif ($isQuery) {
                # code...
            } else {
                $defaultHeaders[] = 'Content-Type: application/json';
            }
                    

            $effectiveHeaders = array_merge($defaultHeaders, $headers);

            if($effectiveHeaders){
                curl_setopt($ch, CURLOPT_HTTPHEADER, $effectiveHeaders);
            }
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
            curl_setopt($ch, CURLOPT_URL, $url);
            curl_setopt($ch, CURLOPT_CONNECTTIMEOUT,10);
            curl_setopt($ch, CURLOPT_TIMEOUT,10);  
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
            curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);

            if (!empty($post_arr) || $method == 'POST') { 
                curl_setopt($ch, CURLOPT_POST, true);
            }
            // 自动识别是否为 POST 请求
            if (!empty($post_arr)) {
               
                if ($isFormRequest) {
                    curl_setopt($ch, CURLOPT_POSTFIELDS, $post_arr);
                } elseif ($isQuery) {
    
                    curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($post_arr));
                } else {
                    curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($post_arr));
                }
            }

            $output = curl_exec($ch);

            if ($error = curl_error($ch)) {
                curl_close($ch);
                throw new \Exception($error, 1);
            }
            $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); // 获取 HTTP 状态码
            $contentType = curl_getinfo($ch, CURLINFO_CONTENT_TYPE);
            curl_close($ch);
            //
            if ($httpCode >= 400) {
                $output_json = json_decode($output, true);
                if($output_json && isset($output_json['success']) && !$output_json['success'] && isset($output_json['message'])){
                    exitJson(-1,$this->apiName.$urlPath.'接口异常:' . $output_json['message']); 
                }
                errorLog(['url' => $url, 'post' => $post_arr, 'html' => $output, 'httpCode' => $httpCode], 'aiimage');
                exitJson(-1, $this->apiName.$urlPath. '接口异常: 服务器错误 (HTTP ' . $httpCode . ')');
            }
            if (strpos($contentType, 'image/') !== 0) {
                $output_json = json_decode($output, true);
                if($output_json && isset($output_json['code']) && $output_json['code']!=0 && isset($output_json['msg'])){
                    exitJson(-1,$this->apiName.$urlPath.'接口异常:' . $output_json['msg']); 
                }
                return $output_json ?: $output;
            }
            
            errorLog(['url' => $url, 'post' => $post_arr, 'html' => $output], 'aiimage');
            exitJson(-1,$this->apiName.$urlPath.'接口异常:' . $output);

        } catch (\Exception $e) {
            errorLog(['url' => $url, 'post' => $post_arr, 'html' => $e->getMessage()], 'aiimage');
            exitJson(-1,$this->apiName.$urlPath.'接口异常:' . $e->getMessage());
        }
    }    


    /**
     * 获取源图片的MD5值
     * @param $source 图片源（URL、文件路径或base64）
     * @return string MD5值
     */
    private function getSourceMd5($source)
    {
        // 统一转换为base64格式后再计算MD5
        $base64Content = $this->convertToBase64($source);
        
        if ($base64Content) {
            // 提取base64数据部分（去掉data:image/xxx;base64,前缀）
            if (preg_match('/^data:image\/\w+;base64,(.+)$/', $base64Content, $matches)) {
                $imageData = $matches[1];
                // 解码base64内容并计算MD5
                $decodedData = base64_decode($imageData);
                return md5($decodedData);
            } else {
                // 如果不是标准base64格式，直接计算内容MD5
                return md5($base64Content);
            }
        } else {
            // 如果转换失败，使用原始数据计算MD5
            return md5($source);
        }
    }

    /**
     * 将各种类型的图片源转换为base64格式
     * @param $source 图片源（URL、文件路径或base64）
     * @return string base64格式的图片
     */
    private function convertToBase64($source)
    {
        if (stripos($source, 'http') === 0) {
            // URL格式，下载图片内容
            $ch = curl_init();
            curl_setopt($ch, CURLOPT_URL, $source);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
            curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
            curl_setopt($ch, CURLOPT_TIMEOUT, 30);
            
            $imageData = curl_exec($ch);
            $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
            curl_close($ch);
            
            if ($httpCode == 200 && $imageData !== false) {
                // 根据实际图片类型确定MIME类型
                $finfo = finfo_open(FILEINFO_MIME_TYPE);
                $mimeType = finfo_buffer($finfo, $imageData);
                finfo_close($finfo);
                
                // 如果无法检测到MIME类型，默认使用jpeg
                if (!$mimeType || strpos($mimeType, 'image') === false) {
                    $mimeType = 'image/jpeg';
                }
                
                return 'data:' . $mimeType . ';base64,' . base64_encode($imageData);
            }
            return false;
        } elseif (preg_match('/^data:image\/(\w+);base64,/', $source)) {
            // 已经是base64格式，直接返回
            return $source;
        } else {
            // 文件路径格式，读取文件内容
            if (file_exists($source)) {
                $imageData = file_get_contents($source);
                if ($imageData !== false) {
                    // 获取文件扩展名以确定MIME类型
                    $extension = strtolower(pathinfo($source, PATHINFO_EXTENSION));
                    switch ($extension) {
                        case 'jpg':
                        case 'jpeg':
                            $mimeType = 'image/jpeg';
                            break;
                        case 'png':
                            $mimeType = 'image/png';
                            break;
                        case 'gif':
                            $mimeType = 'image/gif';
                            break;
                        case 'webp':
                            $mimeType = 'image/webp';
                            break;
                        default:
                            // 使用finfo检测MIME类型
                            $finfo = finfo_open(FILEINFO_MIME_TYPE);
                            $mimeType = finfo_file($finfo, $source);
                            finfo_close($finfo);
                            if (!$mimeType || strpos($mimeType, 'image') === false) {
                                $mimeType = 'image/jpeg';
                            }
                    }
                    
                    return 'data:' . $mimeType . ';base64,' . base64_encode($imageData);
                }
            }
            return false;
        }
    }
}   