package com.xyw.console.asset.service;

import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;

import com.xyw.console.asset.exception.DeviceAssetValidationException;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import javax.imageio.ImageIO;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import org.springframework.mock.web.MockMultipartFile;

/** 文件用途（白话）：验证设备图片的格式、大小、路径约束和失败清理，不依赖真实上传目录。 */
class DeviceAssetFileStorageServiceTest {
  /** 代码作用（白话）：验证合法 PNG 会存为不透明标识，且失败清理后不能再次读取。关联文件：DeviceAssetFileStorageService.java。关联逻辑（调用链/数据流）：图片 -> store -> 标识 -> cleanupNewFile -> 受控读取失败。 */
  @Test void storesAndCleansOnlyNewImage(@TempDir Path directory) throws Exception {
    DeviceAssetFileStorageService storage=new DeviceAssetFileStorageService(directory.toString());String identifier=storage.store(new MockMultipartFile("image","one.png","image/png",png()));
    assertTrue(Files.exists(directory.resolve(identifier)));storage.cleanupNewFile(identifier);assertThrows(DeviceAssetValidationException.class,()->storage.resolve(identifier));
  }
  /** 代码作用（白话）：验证允许的 JPG、PNG、GIF 都会经过真实图片解码后保存。关联文件：DeviceAssetFileStorageService.java。关联逻辑（调用链/数据流）：三种 MultipartFile -> validateImage -> store -> 受控文件目录。*/
  @Test void storesEverySupportedImageFormat(@TempDir Path directory) throws Exception {
    DeviceAssetFileStorageService storage=new DeviceAssetFileStorageService(directory.toString());
    assertTrue(Files.exists(directory.resolve(storage.store(new MockMultipartFile("image","one.jpg","image/jpeg",image("jpg"))))));
    assertTrue(Files.exists(directory.resolve(storage.store(new MockMultipartFile("image","two.png","image/png",image("png"))))));
    assertTrue(Files.exists(directory.resolve(storage.store(new MockMultipartFile("image","three.gif","image/gif",image("gif"))))));
  }
  /** 代码作用（白话）：验证损坏、超限和不支持类型会在保存前被拒绝。关联文件：DeviceAssetFileStorageService.java。关联逻辑（调用链/数据流）：multipart 文件 -> validateImage -> 400 业务异常。 */
  @Test void rejectsCorruptedOversizedAndUnsupportedImages(@TempDir Path directory) {
    DeviceAssetFileStorageService storage=new DeviceAssetFileStorageService(directory.toString());assertThrows(DeviceAssetValidationException.class,()->storage.store(new MockMultipartFile("image","bad.png","image/png",new byte[]{1,2,3})));assertThrows(DeviceAssetValidationException.class,()->storage.store(new MockMultipartFile("image","bad.txt","text/plain",png())));assertThrows(DeviceAssetValidationException.class,()->storage.store(new MockMultipartFile("image","large.png","image/png",new byte[20*1024*1024+1])));
  }
  /** 代码作用（白话）：验证文件标识不能离开设备图片根目录。关联文件：DeviceAssetFileStorageService.java、DeviceAssetController.java。关联逻辑（调用链/数据流）：图片 URL 标识 -> resolve -> 根目录校验。 */
  @Test void rejectsPathTraversalIdentifier(@TempDir Path directory) { DeviceAssetFileStorageService storage=new DeviceAssetFileStorageService(directory.toString());assertThrows(DeviceAssetValidationException.class,()->storage.resolve("../secret.png")); }
  /** 代码作用（白话）：在测试中生成 ImageIO 必然可解码的 PNG 字节。关联文件：DeviceAssetFileStorageService.java。关联逻辑（调用链/数据流）：BufferedImage -> PNG 字节 -> MockMultipartFile -> 服务校验。 */
  private byte[] png() { try { ByteArrayOutputStream output=new ByteArrayOutputStream();ImageIO.write(new BufferedImage(1,1,BufferedImage.TYPE_INT_ARGB),"png",output);return output.toByteArray(); } catch(Exception exception) { throw new IllegalStateException(exception); } }
  /** 代码作用（白话）：按指定格式生成可被 ImageIO 解码的小图片，避免测试数据本身失真。关联文件：DeviceAssetFileStorageService.java。关联逻辑（调用链/数据流）：BufferedImage -> 指定格式字节 -> MockMultipartFile -> 上传格式校验。*/
  private byte[] image(String format) { try { ByteArrayOutputStream output=new ByteArrayOutputStream();if(!ImageIO.write(new BufferedImage(1,1,BufferedImage.TYPE_INT_RGB),format,output)){throw new IllegalStateException("测试运行环境不支持图片格式："+format);}return output.toByteArray(); } catch(Exception exception) { throw new IllegalStateException(exception); } }
}
