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

import com.ycwl.basic.image.enhancer.entity.BceEnhancerConfig;
import com.ycwl.basic.image.pipeline.core.PhotoProcessContext;
import com.ycwl.basic.pipeline.core.StageResult;
import com.ycwl.basic.image.pipeline.enums.ImageSource;
import com.ycwl.basic.image.pipeline.enums.ImageType;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;

import java.io.File;
import java.io.FileOutputStream;
import java.nio.file.Path;

import static org.junit.jupiter.api.Assertions.*;

/**
 * ImageEnhanceStage 单元测试
 */
class ImageEnhanceStageTest {

    @Test
    void testGetName() {
        ImageEnhanceStage stage = new ImageEnhanceStage();

        assertEquals("ImageEnhanceStage", stage.getName());
    }

    @Test
    void testDefaultConstructor_ShouldSetDefaultConfig() {
        ImageEnhanceStage stage = new ImageEnhanceStage();

        BceEnhancerConfig config = stage.getEnhancerConfig();

        assertNotNull(config);
        assertEquals(1.0f, config.getQps());
        assertEquals(System.getenv("BCE_IMAGE_APP_ID"), config.getAppId());
        assertEquals(System.getenv("BCE_IMAGE_API_KEY"), config.getApiKey());
        assertEquals(System.getenv("BCE_IMAGE_SECRET_KEY"), config.getSecretKey());
    }

    @Test
    void testConstructorWithConfig() {
        BceEnhancerConfig customConfig = new BceEnhancerConfig();
        customConfig.setAppId("custom-app-id");
        customConfig.setApiKey("custom-api-key");
        customConfig.setSecretKey("custom-secret-key");
        customConfig.setQps(2.0f);

        ImageEnhanceStage stage = new ImageEnhanceStage(customConfig);

        BceEnhancerConfig config = stage.getEnhancerConfig();
        assertEquals("custom-app-id", config.getAppId());
        assertEquals("custom-api-key", config.getApiKey());
        assertEquals("custom-secret-key", config.getSecretKey());
        assertEquals(2.0f, config.getQps());
    }

    @Test
    void testShouldExecute_IPCSource() {
        ImageEnhanceStage stage = new ImageEnhanceStage();

        PhotoProcessContext context = PhotoProcessContext.builder()
                .originalUrl("https://example.com/test.jpg")
                .scenicId(123L)
                .source(ImageSource.IPC)
                .build();

        // 需要显式启用 image_enhance
        context.loadStageConfig(null, java.util.Map.of("image_enhance", true));

        assertTrue(stage.shouldExecute(context));
    }

    @Test
    void testShouldExecute_PhoneSource_ShouldSkip() {
        ImageEnhanceStage stage = new ImageEnhanceStage();

        PhotoProcessContext context = PhotoProcessContext.builder()
                .originalUrl("https://example.com/test.jpg")
                .scenicId(123L)
                .source(ImageSource.PHONE)
                .build();

        context.loadStageConfig(null, java.util.Map.of("image_enhance", true));

        assertFalse(stage.shouldExecute(context));
    }

    @Test
    void testShouldExecute_CameraSource_ShouldSkip() {
        ImageEnhanceStage stage = new ImageEnhanceStage();

        PhotoProcessContext context = PhotoProcessContext.builder()
                .originalUrl("https://example.com/test.jpg")
                .scenicId(123L)
                .source(ImageSource.CAMERA)
                .build();

        context.loadStageConfig(null, java.util.Map.of("image_enhance", true));

        assertFalse(stage.shouldExecute(context));
    }

    @Test
    void testShouldExecute_UnknownSource_ShouldSkip() {
        ImageEnhanceStage stage = new ImageEnhanceStage();

        PhotoProcessContext context = PhotoProcessContext.builder()
                .originalUrl("https://example.com/test.jpg")
                .scenicId(123L)
                .source(ImageSource.UNKNOWN)
                .build();

        context.loadStageConfig(null, java.util.Map.of("image_enhance", true));

        assertFalse(stage.shouldExecute(context));
    }

    @Test
    void testShouldExecute_NullSource_ShouldSkip() {
        ImageEnhanceStage stage = new ImageEnhanceStage();

        PhotoProcessContext context = PhotoProcessContext.builder()
                .originalUrl("https://example.com/test.jpg")
                .scenicId(123L)
                .build();

        context.loadStageConfig(null, java.util.Map.of("image_enhance", true));

        assertFalse(stage.shouldExecute(context));
    }

    @Test
    void testShouldExecute_DisabledByConfig_ShouldSkip() {
        ImageEnhanceStage stage = new ImageEnhanceStage();

        PhotoProcessContext context = PhotoProcessContext.builder()
                .originalUrl("https://example.com/test.jpg")
                .scenicId(123L)
                .source(ImageSource.IPC)
                .build();

        // 默认不启用，不加载配置
        assertFalse(stage.shouldExecute(context));
    }

    @Test
    void testExecute_NoCurrentFile_ShouldSkip() {
        BceEnhancerConfig validConfig = new BceEnhancerConfig();
        validConfig.setAppId("valid-app-id");
        validConfig.setApiKey("valid-api-key");
        validConfig.setSecretKey("valid-secret-key");

        ImageEnhanceStage stage = new ImageEnhanceStage(validConfig);

        PhotoProcessContext context = PhotoProcessContext.builder()
                .originalUrl("https://example.com/test.jpg")
                .scenicId(123L)
                .source(ImageSource.IPC)
                .build();

        StageResult result = stage.execute(context);

        assertTrue(result.isSkipped());
        assertEquals("当前文件不存在", result.getMessage());
    }

    @Test
    void testExecute_InvalidConfig_ShouldSkip() {
        // 创建无效配置（使用 TODO 占位符）
        BceEnhancerConfig invalidConfig = new BceEnhancerConfig();
        invalidConfig.setAppId("TODO_YOUR_APP_ID");
        invalidConfig.setApiKey("TODO_YOUR_API_KEY");
        invalidConfig.setSecretKey("TODO_YOUR_SECRET_KEY");

        ImageEnhanceStage stage = new ImageEnhanceStage(invalidConfig);

        PhotoProcessContext context = PhotoProcessContext.builder()
                .processId("test-invalid-config")
                .originalUrl("https://example.com/test.jpg")
                .scenicId(123L)
                .source(ImageSource.IPC)
                .build();

        // 创建一个临时文件
        File tempFile = context.getTempFileManager().createTempFile("test", ".jpg");
        context.setOriginalFile(tempFile);

        StageResult result = stage.execute(context);

        assertTrue(result.isSkipped());
        assertEquals("配置不完整，跳过增强", result.getMessage());
    }

    @Test
    void testExecute_NullConfig_ShouldSkip(@TempDir Path tempDir) throws Exception {
        ImageEnhanceStage stage = new ImageEnhanceStage(null);

        PhotoProcessContext context = PhotoProcessContext.builder()
                .processId("test-null-config")
                .originalUrl("https://example.com/test.jpg")
                .scenicId(123L)
                .source(ImageSource.IPC)
                .build();

        // 创建一个临时文件
        File testFile = tempDir.resolve("test.jpg").toFile();
        try (FileOutputStream fos = new FileOutputStream(testFile)) {
            fos.write(new byte[]{1, 2, 3, 4, 5});
        }
        context.setOriginalFile(testFile);

        StageResult result = stage.execute(context);

        assertTrue(result.isSkipped());
        assertEquals("配置不完整，跳过增强", result.getMessage());
    }

    @Test
    void testExecute_NullAppId_ShouldSkip(@TempDir Path tempDir) throws Exception {
        BceEnhancerConfig config = new BceEnhancerConfig();
        config.setAppId(null);
        config.setApiKey("valid-api-key");
        config.setSecretKey("valid-secret-key");

        ImageEnhanceStage stage = new ImageEnhanceStage(config);

        PhotoProcessContext context = PhotoProcessContext.builder()
                .processId("test-null-appid")
                .originalUrl("https://example.com/test.jpg")
                .scenicId(123L)
                .source(ImageSource.IPC)
                .build();

        File testFile = tempDir.resolve("test.jpg").toFile();
        try (FileOutputStream fos = new FileOutputStream(testFile)) {
            fos.write(new byte[]{1, 2, 3, 4, 5});
        }
        context.setOriginalFile(testFile);

        StageResult result = stage.execute(context);

        assertTrue(result.isSkipped());
        assertEquals("配置不完整，跳过增强", result.getMessage());
    }

    @Test
    void testExecute_TodoPlaceholderAppId_ShouldSkip(@TempDir Path tempDir) throws Exception {
        BceEnhancerConfig config = new BceEnhancerConfig();
        config.setAppId("TODO_APP_ID");
        config.setApiKey("valid-api-key");
        config.setSecretKey("valid-secret-key");

        ImageEnhanceStage stage = new ImageEnhanceStage(config);

        PhotoProcessContext context = PhotoProcessContext.builder()
                .processId("test-todo-appid")
                .originalUrl("https://example.com/test.jpg")
                .scenicId(123L)
                .source(ImageSource.IPC)
                .build();

        File testFile = tempDir.resolve("test.jpg").toFile();
        try (FileOutputStream fos = new FileOutputStream(testFile)) {
            fos.write(new byte[]{1, 2, 3, 4, 5});
        }
        context.setOriginalFile(testFile);

        StageResult result = stage.execute(context);

        assertTrue(result.isSkipped());
        assertEquals("配置不完整，跳过增强", result.getMessage());
    }

    @Test
    void testSetAndGetEnhancerConfig() {
        ImageEnhanceStage stage = new ImageEnhanceStage();

        BceEnhancerConfig newConfig = new BceEnhancerConfig();
        newConfig.setAppId("new-app-id");
        newConfig.setApiKey("new-api-key");
        newConfig.setSecretKey("new-secret-key");
        newConfig.setQps(3.0f);

        stage.setEnhancerConfig(newConfig);

        BceEnhancerConfig retrieved = stage.getEnhancerConfig();
        assertEquals("new-app-id", retrieved.getAppId());
        assertEquals("new-api-key", retrieved.getApiKey());
        assertEquals("new-secret-key", retrieved.getSecretKey());
        assertEquals(3.0f, retrieved.getQps());
    }

    @Test
    void testExecute_AllImageTypes_WithIPCSource(@TempDir Path tempDir) throws Exception {
        ImageEnhanceStage stage = new ImageEnhanceStage();

        // 测试普通照片
        testImageType(stage, tempDir, ImageType.NORMAL_PHOTO);

        // 测试拼图
        testImageType(stage, tempDir, ImageType.PUZZLE);

        // 测试手机上传
        testImageType(stage, tempDir, ImageType.MOBILE_UPLOAD);
    }

    private void testImageType(ImageEnhanceStage stage, Path tempDir, ImageType imageType) throws Exception {
        PhotoProcessContext context = PhotoProcessContext.builder()
                .processId("test-" + imageType.getCode())
                .originalUrl("https://example.com/test.jpg")
                .scenicId(123L)
                .imageType(imageType)
                .source(ImageSource.IPC)
                .build();

        File testFile = tempDir.resolve("test-" + imageType.getCode() + ".jpg").toFile();
        try (FileOutputStream fos = new FileOutputStream(testFile)) {
            fos.write(new byte[]{1, 2, 3, 4, 5});
        }
        context.setOriginalFile(testFile);

        context.loadStageConfig(null, java.util.Map.of("image_enhance", true));

        // 应该可以执行（因为 source 是 IPC）
        assertTrue(stage.shouldExecute(context));
    }

    @Test
    void testConfigValidation_AllTodoFields() {
        BceEnhancerConfig config = new BceEnhancerConfig();
        config.setAppId("TODO_APP_ID");
        config.setApiKey("TODO_API_KEY");
        config.setSecretKey("TODO_SECRET_KEY");

        ImageEnhanceStage stage = new ImageEnhanceStage(config);

        PhotoProcessContext context = PhotoProcessContext.builder()
                .processId("test-all-todo")
                .originalUrl("https://example.com/test.jpg")
                .scenicId(123L)
                .source(ImageSource.IPC)
                .build();

        File tempFile = context.getTempFileManager().createTempFile("test", ".jpg");
        context.setOriginalFile(tempFile);

        StageResult result = stage.execute(context);

        assertTrue(result.isSkipped());
    }

    @Test
    void testConfigValidation_MixedTodoAndValid() {
        BceEnhancerConfig config = new BceEnhancerConfig();
        config.setAppId("valid-app-id");
        config.setApiKey("TODO_API_KEY");
        config.setSecretKey("valid-secret-key");

        ImageEnhanceStage stage = new ImageEnhanceStage(config);

        PhotoProcessContext context = PhotoProcessContext.builder()
                .processId("test-mixed-todo")
                .originalUrl("https://example.com/test.jpg")
                .scenicId(123L)
                .source(ImageSource.IPC)
                .build();

        File tempFile = context.getTempFileManager().createTempFile("test", ".jpg");
        context.setOriginalFile(tempFile);

        StageResult result = stage.execute(context);

        assertTrue(result.isSkipped());
    }

    /**
     * 测试说明：
     *
     * 由于 ImageEnhanceStage 依赖外部 API (BceImageEnhancer)，
     * 以下测试场景需要 Mock 或集成测试环境：
     *
     * 1. testExecute_Success_ValidConfig()
     *    - 模拟成功的图像增强调用
     *    - 验证增强后文件大小变化
     *    - 验证 context.updateProcessedFile() 被调用
     *
     * 2. testExecute_ApiReturnsNull_ShouldDegrade()
     *    - 模拟 API 返回 null
     *    - 验证返回 StageResult.degraded()
     *
     * 3. testExecute_ApiReturnsEmptyFile_ShouldDegrade()
     *    - 模拟 API 返回空文件
     *    - 验证返回 StageResult.degraded()
     *
     * 4. testExecute_ApiThrowsException_ShouldDegrade()
     *    - 模拟 API 抛出异常
     *    - 验证返回 StageResult.degraded() 而不是 failed()
     *
     * 5. testExecute_SaveFileFails_ShouldDegrade()
     *    - 模拟文件保存失败
     *    - 验证返回 StageResult.degraded()
     *
     * 这些测试需要使用 Mockito 或类似的 Mock 框架来模拟 BceImageEnhancer 的行为。
     *
     * 示例（使用 Mockito）：
     *
     * @Test
     * void testExecute_Success_ValidConfig() {
     *     // 创建 Mock 的 BceImageEnhancer
     *     BceImageEnhancer mockEnhancer = mock(BceImageEnhancer.class);
     *
     *     // 创建 Mock 的 MultipartFile
     *     MultipartFile mockEnhancedImage = mock(MultipartFile.class);
     *     when(mockEnhancedImage.isEmpty()).thenReturn(false);
     *     when(mockEnhancedImage.getBytes()).thenReturn(new byte[]{1, 2, 3, 4, 5, 6, 7, 8});
     *
     *     // 配置 Mock 行为
     *     when(mockEnhancer.enhance(anyString())).thenReturn(mockEnhancedImage);
     *
     *     // 测试逻辑...
     * }
     */
}
