package com.ycwl.basic.image.watermark.edge;

import cn.hutool.core.date.DateUtil;
import cn.hutool.http.HttpUtil;
import com.ycwl.basic.constant.StorageConstant;
import com.ycwl.basic.image.watermark.entity.WatermarkInfo;
import com.ycwl.basic.image.watermark.enums.ImageWatermarkOperatorEnum;
import com.ycwl.basic.puzzle.edge.task.PuzzleEdgeRenderTaskService;
import com.ycwl.basic.storage.StorageFactory;
import com.ycwl.basic.storage.adapters.IStorageAdapter;
import com.ycwl.basic.storage.enums.StorageAcl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.Date;
import java.util.List;
import java.util.UUID;

/**
 * 水印边缘端处理服务
 * 将原有的 IOperator 本地处理迁移到边缘端渲染
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class WatermarkEdgeService {

    private final WatermarkEdgeTaskCreator watermarkEdgeTaskCreator;

    /**
     * 默认等待超时时间（毫秒）
     */
    private static final long DEFAULT_TIMEOUT_MS = 30_000L;

    /**
     * 使用边缘端处理水印（适用于 GoodsServiceImpl 场景）
     * 直接传入 URL，不需要本地文件
     *
     * @param type           水印类型
     * @param originalUrl    原图URL
     * @param qrcodeUrl      二维码URL
     * @param faceUrl        头像URL（可选）
     * @param scenicLine     景区名称
     * @param datetime       日期时间
     * @param dtFormat       日期格式
     * @param sourceId       关联的sourceId（用于记录追踪）
     * @param faceId         人脸ID（可选）
     * @return 带水印的图片URL，处理失败返回null
     */
    public String processWatermark(ImageWatermarkOperatorEnum type,
                                   String originalUrl,
                                   String qrcodeUrl,
                                   String faceUrl,
                                   String scenicLine,
                                   Date datetime,
                                   String dtFormat,
                                   Long sourceId,
                                   Long faceId) {
        return processWatermark(type, originalUrl, qrcodeUrl, faceUrl, scenicLine, datetime, dtFormat,
                sourceId, faceId, null, null, null, null, null);
    }

    /**
     * 使用边缘端处理水印（完整参数版本）
     *
     * @param type           水印类型
     * @param originalUrl    原图URL
     * @param qrcodeUrl      二维码URL
     * @param faceUrl        头像URL（可选）
     * @param scenicLine     景区名称
     * @param datetime       日期时间
     * @param dtFormat       日期格式
     * @param sourceId       关联的sourceId（用于记录追踪）
     * @param faceId         人脸ID（可选）
     * @param scale          缩放倍数（可选）
     * @param offsetLeft     左偏移（可选）
     * @param offsetRight    右偏移（可选）
     * @param offsetTop      上偏移（可选）
     * @param offsetBottom   下偏移（可选）
     * @return 带水印的图片URL，处理失败返回null
     */
    public String processWatermark(ImageWatermarkOperatorEnum type,
                                   String originalUrl,
                                   String qrcodeUrl,
                                   String faceUrl,
                                   String scenicLine,
                                   Date datetime,
                                   String dtFormat,
                                   Long sourceId,
                                   Long faceId,
                                   Double scale,
                                   Integer offsetLeft,
                                   Integer offsetRight,
                                   Integer offsetTop,
                                   Integer offsetBottom) {
        // 将 ImageWatermarkOperatorEnum 映射到边缘端风格
        String style = mapTypeToStyle(type);

        // 检查边缘端是否支持该风格
        if (!watermarkEdgeTaskCreator.isStyleSupported(style)) {
            log.warn("边缘端不支持水印风格: {}", style);
            return null;
        }

        try {
            // 获取图片尺寸
            int[] dimensions = getImageDimensions(originalUrl);
            if (dimensions == null) {
                log.error("无法获取图片尺寸: {}", originalUrl);
                return null;
            }

            // 构建日期时间行
            String datetimeLine = datetime != null && dtFormat != null
                    ? DateUtil.format(datetime, dtFormat)
                    : null;

            // 构建水印请求
            WatermarkRequest request = WatermarkRequest.builder()
                    .originalImageUrl(originalUrl)
                    .imageWidth(dimensions[0])
                    .imageHeight(dimensions[1])
                    .qrcodeUrl(qrcodeUrl)
                    .faceUrl(faceUrl)
                    .scenicLine(scenicLine)
                    .datetimeLine(datetimeLine)
                    .scale(scale)
                    .offsetLeft(offsetLeft)
                    .offsetRight(offsetRight)
                    .offsetTop(offsetTop)
                    .offsetBottom(offsetBottom)
                    .outputFormat(type.getPreferFileType().equalsIgnoreCase("png") ? "PNG" : "JPEG")
                    .outputQuality(90)
                    .build();

            // 创建边缘任务并等待结果
            PuzzleEdgeRenderTaskService.TaskWaitResult result = watermarkEdgeTaskCreator.createAndWait(
                    style,
                    request,
                    sourceId,  // recordId
                    faceId,
                    type.getType(),  // watermarkType
                    DEFAULT_TIMEOUT_MS
            );

            if (result.isSuccess()) {
                log.info("边缘端水印处理成功: sourceId={}, type={}, url={}", sourceId, type, result.getImageUrl());
                return result.getImageUrl();
            } else {
                log.error("边缘端水印处理失败: sourceId={}, type={}, error={}", sourceId, type, result.getErrorMessage());
                return null;
            }
        } catch (Exception e) {
            log.error("边缘端水印处理异常: sourceId={}, type={}", sourceId, type, e);
            return null;
        }
    }

    /**
     * 使用边缘端处理水印（适用于 WatermarkStage / Pipeline 场景）
     * 从本地文件处理，需要先上传原图和二维码
     *
     * @param info           水印信息（包含本地文件）
     * @param type           水印类型
     * @param adapter        存储适配器
     * @param recordId       记录ID（用于边缘端任务追踪，不能为空）
     * @return 处理后的本地文件，失败返回null
     */
    public File processWatermarkFromFile(WatermarkInfo info,
                                         ImageWatermarkOperatorEnum type,
                                         IStorageAdapter adapter,
                                         String recordId) {
        // 将 ImageWatermarkOperatorEnum 映射到边缘端风格
        String style = mapTypeToStyle(type);

        // 检查边缘端是否支持该风格
        if (!watermarkEdgeTaskCreator.isStyleSupported(style)) {
            log.warn("边缘端不支持水印风格: {}", style);
            return null;
        }

        String uploadedOriginalUrl = null;
        String uploadedQrcodeUrl = null;
        String uploadedFaceUrl = null;

        try {
            // 1. 获取图片尺寸
            BufferedImage originalImage = ImageIO.read(info.getOriginalFile());
            if (originalImage == null) {
                log.error("无法读取原图文件: {}", info.getOriginalFile());
                return null;
            }
            int imageWidth = originalImage.getWidth();
            int imageHeight = originalImage.getHeight();
            originalImage.flush();

            // 2. 上传原图到临时位置
            String originalFileName = "temp_watermark_" + UUID.randomUUID() + ".jpg";
            uploadedOriginalUrl = adapter.uploadFile(null, info.getOriginalFile(),
                    StorageConstant.PHOTO_WATERMARKED_PATH + "/temp", originalFileName);
            adapter.setAcl(StorageAcl.PUBLIC_READ, StorageConstant.PHOTO_WATERMARKED_PATH + "/temp", originalFileName);

            // 3. 上传二维码（如果有）
            if (info.getQrcodeFile() != null && info.getQrcodeFile().exists()) {
                String qrcodeFileName = "temp_qrcode_" + UUID.randomUUID() + ".jpg";
                uploadedQrcodeUrl = adapter.uploadFile(null, info.getQrcodeFile(),
                        StorageConstant.PHOTO_WATERMARKED_PATH + "/temp", qrcodeFileName);
                adapter.setAcl(StorageAcl.PUBLIC_READ, StorageConstant.PHOTO_WATERMARKED_PATH + "/temp", qrcodeFileName);
            }

            // 4. 上传头像（如果有）
            if (info.getFaceFile() != null && info.getFaceFile().exists()) {
                String faceFileName = "temp_face_" + UUID.randomUUID() + ".jpg";
                uploadedFaceUrl = adapter.uploadFile(null, info.getFaceFile(),
                        StorageConstant.PHOTO_WATERMARKED_PATH + "/temp", faceFileName);
                adapter.setAcl(StorageAcl.PUBLIC_READ, StorageConstant.PHOTO_WATERMARKED_PATH + "/temp", faceFileName);
            }

            // 5. 构建水印请求
            WatermarkRequest request = WatermarkRequest.builder()
                    .originalImageUrl(uploadedOriginalUrl)
                    .imageWidth(imageWidth)
                    .imageHeight(imageHeight)
                    .qrcodeUrl(uploadedQrcodeUrl)
                    .faceUrl(uploadedFaceUrl)
                    .scenicLine(info.getScenicLine())
                    .datetimeLine(info.getDatetimeLine())
                    .scale(info.getScale())
                    .offsetLeft(info.getOffsetLeft())
                    .offsetRight(info.getOffsetRight())
                    .offsetTop(info.getOffsetTop())
                    .offsetBottom(info.getOffsetBottom())
                    .printWatermarkUrl(resolvePrintWatermarkUrl(imageWidth, imageHeight,
                            info.getPrintWatermarkPUrlList(), info.getPrintWatermarkLUrlList()))
                    .outputFormat(type.getPreferFileType().equalsIgnoreCase("png") ? "PNG" : "JPEG")
                    .outputQuality(90)
                    .build();

            // 6. 创建边缘任务并等待结果（使用传入的 recordId）
            // recordId 转换为 Long，如果无法转换则使用哈希值
            Long recordIdLong;
            try {
                recordIdLong = Long.parseLong(recordId);
            } catch (NumberFormatException e) {
                // 如果 recordId 不是数字（如 UUID），使用其哈希值的绝对值
                recordIdLong = (long) Math.abs(recordId.hashCode());
            }

            PuzzleEdgeRenderTaskService.TaskWaitResult result = watermarkEdgeTaskCreator.createAndWait(
                    style,
                    request,
                    recordIdLong,  // recordId
                    null,  // faceId
                    type.getType(),  // watermarkType
                    DEFAULT_TIMEOUT_MS
            );

            if (!result.isSuccess()) {
                log.error("边缘端水印处理失败: recordId={}, error={}", recordId, result.getErrorMessage());
                return null;
            }

            // 7. 下载结果到目标文件
            String resultUrl = result.getImageUrl();
            File outputFile = info.getWatermarkedFile();
            downloadFile(resultUrl, outputFile);

            log.info("边缘端水印处理成功: recordId={}, type={}, outputFile={}", recordId, type, outputFile);
            return outputFile;

        } catch (Exception e) {
            log.error("边缘端水印处理异常: recordId={}, type={}", recordId, type, e);
            return null;
        }
    }

    /**
     * 将 ImageWatermarkOperatorEnum 映射到边缘端风格
     */
    private String mapTypeToStyle(ImageWatermarkOperatorEnum type) {
        if (type == null) {
            return null;
        }
        return switch (type) {
            case NORMAL -> NormalWatermarkTemplateBuilder.STYLE;
            case LEICA -> LeicaWatermarkTemplateBuilder.STYLE;
            case PRINTER_DEFAULT -> PrinterDefaultWatermarkTemplateBuilder.STYLE;
            case PUZZLE_PRINT -> PuzzlePrintWatermarkTemplateBuilder.STYLE;
        };
    }

    /**
     * 根据图片方向从URL列表中选取对应的打印水印URL
     *
     * @param imageWidth  图片宽度
     * @param imageHeight 图片高度
     * @param pUrlList    竖版URL列表
     * @param lUrlList    横版URL列表
     * @return 选中的URL，无可用URL时返回null
     */
    private String resolvePrintWatermarkUrl(int imageWidth, int imageHeight,
                                            List<String> pUrlList, List<String> lUrlList) {
        boolean isLandscape = imageWidth >= imageHeight;
        List<String> urlList = isLandscape ? lUrlList : pUrlList;
        if (urlList != null && !urlList.isEmpty()) {
            return urlList.get(0);
        }
        return null;
    }

    /**
     * 获取图片尺寸
     *
     * @param imageUrl 图片URL
     * @return [width, height]，失败返回null
     */
    private int[] getImageDimensions(String imageUrl) {
        try {
            // 替换内网域名
            String url = imageUrl.replace("oss.zhentuai.com",
                    "frametour-assets.oss-cn-shanghai-internal.aliyuncs.com");
            BufferedImage image = ImageIO.read(new URL(url));
            if (image == null) {
                return null;
            }
            int[] dimensions = new int[]{image.getWidth(), image.getHeight()};
            image.flush();
            return dimensions;
        } catch (IOException e) {
            log.error("获取图片尺寸失败: {}", imageUrl, e);
            return null;
        }
    }

    /**
     * 下载文件
     */
    private void downloadFile(String url, File targetFile) throws IOException {
        // 替换内网域名
        String downloadUrl = url.replace("oss.zhentuai.com",
                "frametour-assets.oss-cn-shanghai-internal.aliyuncs.com");
        HttpUtil.downloadFile(downloadUrl, targetFile);
    }
}
