package com.ycwl.basic.image.pipeline.stages;

import com.ycwl.basic.image.pipeline.core.PhotoProcessContext;
import com.ycwl.basic.image.pipeline.enums.ImageType;
import com.ycwl.basic.image.watermark.ImageWatermarkFactory;
import com.ycwl.basic.image.watermark.edge.WatermarkEdgeService;
import com.ycwl.basic.image.watermark.entity.WatermarkInfo;
import com.ycwl.basic.image.watermark.enums.ImageWatermarkOperatorEnum;
import com.ycwl.basic.image.watermark.operator.IOperator;
import com.ycwl.basic.pipeline.annotation.StageConfig;
import com.ycwl.basic.pipeline.core.AbstractPipelineStage;
import com.ycwl.basic.pipeline.core.StageResult;
import com.ycwl.basic.pipeline.enums.StageOptionalMode;
import com.ycwl.basic.storage.adapters.IStorageAdapter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.io.File;
import java.util.Arrays;
import java.util.Date;
import java.util.List;

/**
 * 水印处理Stage
 * 支持三级降级: 配置的水印类型 -> PRINTER_DEFAULT -> 无水印
 * 支持边缘端渲染（可选）
 */
@Slf4j
@StageConfig(
    stageId = "watermark",
    optionalMode = StageOptionalMode.SUPPORT,
    description = "水印处理",
    defaultEnabled = true
)
public class WatermarkStage extends AbstractPipelineStage<PhotoProcessContext> {

    private static final int OFFSET_FOR_PRINTER = 40;

    private final WatermarkConfig config;

    /**
     * 构造函数
     *
     * @param config 水印配置
     */
    public WatermarkStage(WatermarkConfig config) {
        this.config = config;
    }

    @Override
    public String getName() {
        return "WatermarkStage";
    }

    @Override
    protected boolean shouldExecuteByBusinessLogic(PhotoProcessContext context) {
        return context.getImageType() == ImageType.NORMAL_PHOTO;
    }

    @Override
    protected StageResult<PhotoProcessContext> doExecute(PhotoProcessContext context) {
        if (config == null || config.getWatermarkType() == null) {
            log.info("未配置水印类型,跳过水印处理");
            return StageResult.skipped("未配置水印");
        }

        ImageWatermarkOperatorEnum watermarkType = config.getWatermarkType();

        List<ImageWatermarkOperatorEnum> fallbackChain = buildFallbackChain(watermarkType);
        log.debug("水印降级链: {}", fallbackChain);

        for (int i = 0; i < fallbackChain.size(); i++) {
            ImageWatermarkOperatorEnum type = fallbackChain.get(i);

            if (type == null) {
                log.warn("所有水印处理均失败,跳过水印");
                return StageResult.degraded("降级: 跳过水印处理");
            }

            try {
                StageResult<PhotoProcessContext> result = applyWatermark(context, type);

                if (i > 0) {
                    String degradeMsg = String.format("降级: %s -> %s",
                            watermarkType.getType(), type.getType());
                    log.warn(degradeMsg);
                    return StageResult.degraded(degradeMsg);
                }

                return result;

            } catch (Exception e) {
                log.warn("水印类型 {} 处理失败: {}", type.getType(), e.getMessage());

                if (i == fallbackChain.size() - 2) {
                    log.warn("所有水印类型均失败,准备跳过水印", e);
                }
            }
        }

        return StageResult.degraded("降级: 跳过水印处理");
    }

    /**
     * 构建降级链
     */
    private List<ImageWatermarkOperatorEnum> buildFallbackChain(ImageWatermarkOperatorEnum primary) {
        if (primary == ImageWatermarkOperatorEnum.PRINTER_DEFAULT) {
            return Arrays.asList(primary, null);
        }
        return Arrays.asList(
                primary,
                ImageWatermarkOperatorEnum.PRINTER_DEFAULT,
                null
        );
    }

    /**
     * 应用水印
     */
    private StageResult<PhotoProcessContext> applyWatermark(PhotoProcessContext context, ImageWatermarkOperatorEnum type)
            throws Exception {

        File currentFile = context.getCurrentFile();
        if (currentFile == null || !currentFile.exists()) {
            throw new IllegalStateException("当前文件不存在");
        }

        String fileExt = type.getPreferFileType();
        File watermarkedFile = context.getTempFileManager()
                .createTempFile("watermark_" + type.getType(), "." + fileExt);

        // 尝试边缘端处理
        if (shouldUseEdgeProcessing(type)) {
            File edgeResult = tryEdgeProcessing(context, type, currentFile, watermarkedFile);
            if (edgeResult != null && edgeResult.exists()) {
                context.updateProcessedFile(edgeResult);
                log.info("边缘端水印应用成功: type={}, size={}KB", type.getType(), edgeResult.length() / 1024);
                return StageResult.success(String.format("水印(边缘端): %s (%dKB)",
                        type.getType(), edgeResult.length() / 1024));
            }
            log.warn("边缘端水印处理失败，降级到本地处理: type={}", type.getType());
        }

        // 本地处理（降级或直接使用）
        WatermarkInfo watermarkInfo = buildWatermarkInfo(context, currentFile, watermarkedFile, type);

        IOperator operator = ImageWatermarkFactory.get(type);
        File result = operator.process(watermarkInfo);

        if (result == null || !result.exists()) {
            throw new RuntimeException("水印处理后文件不存在");
        }

        context.updateProcessedFile(result);
        log.info("水印应用成功: type={}, size={}KB", type.getType(), result.length() / 1024);

        return StageResult.success(String.format("水印: %s (%dKB)",
                type.getType(), result.length() / 1024));
    }

    /**
     * 判断是否应使用边缘端处理
     */
    private boolean shouldUseEdgeProcessing(ImageWatermarkOperatorEnum type) {
        if (!config.isEdgeEnabled()) {
            return false;
        }
        WatermarkEdgeService edgeService = config.getEdgeService();
        if (edgeService == null) {
            return false;
        }
        IStorageAdapter storageAdapter = config.getStorageAdapter();
        return storageAdapter != null;
    }

    /**
     * 尝试使用边缘端处理
     *
     * @return 处理后的文件，失败返回 null
     */
    private File tryEdgeProcessing(PhotoProcessContext context,
                                    ImageWatermarkOperatorEnum type,
                                    File currentFile,
                                    File watermarkedFile) {
        try {
            WatermarkEdgeService edgeService = config.getEdgeService();
            IStorageAdapter storageAdapter = config.getStorageAdapter();

            // 构建水印信息用于边缘端处理
            WatermarkInfo info = buildWatermarkInfo(context, currentFile, watermarkedFile, type);

            // 调用边缘端服务处理，传递 processId 作为 recordId
            return edgeService.processWatermarkFromFile(info, type, storageAdapter, context.getProcessId());

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

    /**
     * 构建水印参数
     */
    private WatermarkInfo buildWatermarkInfo(PhotoProcessContext context, File originalFile,
                                              File watermarkedFile, ImageWatermarkOperatorEnum type) {
        WatermarkInfo info = new WatermarkInfo();
        info.setOriginalFile(originalFile);
        info.setWatermarkedFile(watermarkedFile);

        // 从 config 读取景区文字
        String scenicText = config.getScenicText();
        if (StringUtils.isNotBlank(scenicText)) {
            info.setScenicLine(scenicText);
        }

        // 从 config 读取日期格式
        Date now = new Date();
        String dateFormat = config.getDateFormat();
        info.setDatetime(now);
        info.setDtFormat(dateFormat);

        // 从 config 读取二维码文件
        File qrcodeFile = config.getQrcodeFile();
        if (qrcodeFile != null && qrcodeFile.exists()) {
            info.setQrcodeFile(qrcodeFile);
        }

        // 从 config 读取缩放倍数
        Double scale = config.getScale();
        if (scale != null) {
            info.setScale(scale);
        }

        // 根据旋转状态自己处理 offsetLeft
        if (context.isRotationApplied()) {
            if (context.getImageRotation() == 90) {
                info.setOffsetLeft(OFFSET_FOR_PRINTER);
            } else if (context.getImageRotation() == 270) {
                info.setOffsetRight(OFFSET_FOR_PRINTER);
            }
        }

        // 传递打印水印URL列表（横竖版由边缘端根据图片实际尺寸判断）
        info.setPrintWatermarkPUrlList(config.getPrintWatermarkPUrlList());
        info.setPrintWatermarkLUrlList(config.getPrintWatermarkLUrlList());

        return info;
    }
}
