package com.heyu.api.controller.doc;

import com.heyu.api.baidu.handle.doc.BForgeryDetectionHandle;
import com.heyu.api.baidu.request.doc.BForgeryDetectionRequest;
import com.heyu.api.baidu.response.doc.BForgeryDetectionResp;
import com.heyu.api.data.utils.ApiR;
import com.heyu.api.data.utils.R;
import com.heyu.api.request.doc.ForgeryDetectionRequest;
import com.heyu.api.resp.doc.ForgeryDetectionResp;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

import java.util.ArrayList;
import java.util.List;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.when;

/**
 * ForgeryDetectionController 单元测试
 */
public class ForgeryDetectionControllerTest {

    @InjectMocks
    private ForgeryDetectionController controller;

    @Mock
    private BForgeryDetectionHandle bForgeryDetectionHandle;

    @BeforeEach
    public void setUp() {
        MockitoAnnotations.initMocks(this);
    }

    // ========== 正常流程测试 ==========

    @Test
    public void forgeryDetectionSuccessTest() {
        ForgeryDetectionRequest request = new ForgeryDetectionRequest();
        request.setImageBase64("base64ImageData");

        BForgeryDetectionResp bResp = new BForgeryDetectionResp();
        BForgeryDetectionResp.ResultDTO result = new BForgeryDetectionResp.ResultDTO();
        result.setDetectionResult("fake");
        result.setTamperedProportion(0.85);
        bResp.setResult(result);

        when(bForgeryDetectionHandle.handle(any(BForgeryDetectionRequest.class)))
                .thenReturn(ApiR.setData(bResp));

        R<ForgeryDetectionResp> r = controller.forgeryDetection(request);

        assertNotNull(r);
        assertEquals("200", r.getCode());
        ForgeryDetectionResp resp = r.getData();
        assertNotNull(resp);
        assertEquals("fake", resp.getDetectionResult());
        assertEquals(Double.valueOf(0.85), resp.getTamperedProportion());
    }

    @Test
    public void forgeryDetectionRealImageTest() {
        ForgeryDetectionRequest request = new ForgeryDetectionRequest();
        request.setImageUrl("https://example.com/image.jpg");

        BForgeryDetectionResp bResp = new BForgeryDetectionResp();
        BForgeryDetectionResp.ResultDTO result = new BForgeryDetectionResp.ResultDTO();
        result.setDetectionResult("real");
        bResp.setResult(result);

        when(bForgeryDetectionHandle.handle(any(BForgeryDetectionRequest.class)))
                .thenReturn(ApiR.setData(bResp));

        R<ForgeryDetectionResp> r = controller.forgeryDetection(request);

        assertNotNull(r);
        assertEquals("200", r.getCode());
        assertEquals("real", r.getData().getDetectionResult());
        assertNull(r.getData().getTamperedProportion());
    }

    @Test
    public void forgeryDetectionWithHeatmapTest() {
        ForgeryDetectionRequest request = new ForgeryDetectionRequest();
        request.setImageBase64("base64ImageData");
        request.setReturnHeatmap("true");

        BForgeryDetectionResp bResp = new BForgeryDetectionResp();
        BForgeryDetectionResp.ResultDTO result = new BForgeryDetectionResp.ResultDTO();
        result.setDetectionResult("fake");
        result.setHeatmap("heatmapBase64Data");
        bResp.setResult(result);

        when(bForgeryDetectionHandle.handle(any(BForgeryDetectionRequest.class)))
                .thenReturn(ApiR.setData(bResp));

        R<ForgeryDetectionResp> r = controller.forgeryDetection(request);

        assertEquals("fake", r.getData().getDetectionResult());
        assertEquals("heatmapBase64Data", r.getData().getHeatmap());
    }

    @Test
    public void forgeryDetectionWithTamperedLocationTest() {
        ForgeryDetectionRequest request = new ForgeryDetectionRequest();
        request.setImageBase64("base64ImageData");
        request.setRestrictProbability("0.5");

        BForgeryDetectionResp bResp = new BForgeryDetectionResp();
        BForgeryDetectionResp.ResultDTO result = new BForgeryDetectionResp.ResultDTO();
        result.setDetectionResult("fake");

        List<BForgeryDetectionResp.TamperedLocationDTO> locations = new ArrayList<>();
        BForgeryDetectionResp.TamperedLocationDTO loc = new BForgeryDetectionResp.TamperedLocationDTO();
        loc.setLeft(100);
        loc.setTop(200);
        loc.setWidth(300);
        loc.setHeight(150);
        loc.setProbability(0.95);
        locations.add(loc);
        result.setTamperedLocation(locations);
        bResp.setResult(result);

        when(bForgeryDetectionHandle.handle(any(BForgeryDetectionRequest.class)))
                .thenReturn(ApiR.setData(bResp));

        R<ForgeryDetectionResp> r = controller.forgeryDetection(request);

        ForgeryDetectionResp resp = r.getData();
        assertNotNull(resp.getTamperedLocation());
        assertEquals(1, resp.getTamperedLocation().size());
        ForgeryDetectionResp.TamperedLocation respLoc = resp.getTamperedLocation().get(0);
        assertEquals(Integer.valueOf(100), respLoc.getLeft());
        assertEquals(Integer.valueOf(200), respLoc.getTop());
        assertEquals(Integer.valueOf(300), respLoc.getWidth());
        assertEquals(Integer.valueOf(150), respLoc.getHeight());
        assertEquals(Double.valueOf(0.95), respLoc.getProbability());
    }

    // ========== 异常流程测试 ==========

    @Test
    public void forgeryDetectionHandleErrorTest() {
        ForgeryDetectionRequest request = new ForgeryDetectionRequest();

        when(bForgeryDetectionHandle.handle(any(BForgeryDetectionRequest.class)))
                .thenReturn(ApiR.error("imageUrl和imageBase64不能同时为空"));

        R<ForgeryDetectionResp> r = controller.forgeryDetection(request);

        assertNotNull(r);
        assertEquals("400", r.getCode());
        assertEquals("imageUrl和imageBase64不能同时为空", r.getMsg());
    }

    @Test
    public void forgeryDetectionResultNullTest() {
        ForgeryDetectionRequest request = new ForgeryDetectionRequest();
        request.setImageBase64("data");

        BForgeryDetectionResp bResp = new BForgeryDetectionResp();
        bResp.setResult(null);

        when(bForgeryDetectionHandle.handle(any(BForgeryDetectionRequest.class)))
                .thenReturn(ApiR.setData(bResp));

        R<ForgeryDetectionResp> r = controller.forgeryDetection(request);

        assertNotNull(r);
        assertEquals("400", r.getCode());
    }

    // ========== 请求映射测试 ==========

    @Test
    public void toBaiduRequestMappingTest() {
        ForgeryDetectionRequest request = new ForgeryDetectionRequest();
        request.setImageBase64("base64");
        request.setImageUrl("https://example.com/img.jpg");
        request.setDetectProportion("true");
        request.setDetectThreshold("0.9");
        request.setReturnHeatmap("true");
        request.setRestrictProbability("0.8");

        BForgeryDetectionResp bResp = new BForgeryDetectionResp();
        BForgeryDetectionResp.ResultDTO result = new BForgeryDetectionResp.ResultDTO();
        result.setDetectionResult("real");
        bResp.setResult(result);

        when(bForgeryDetectionHandle.handle(any(BForgeryDetectionRequest.class)))
                .thenAnswer(invocation -> {
                    BForgeryDetectionRequest bReq = invocation.getArgument(0);
                    assertEquals("base64", bReq.getImageBase64());
                    assertEquals("https://example.com/img.jpg", bReq.getImageUrl());
                    assertEquals("true", bReq.getDetectProportion());
                    assertEquals("0.9", bReq.getDetectThreshold());
                    assertEquals("true", bReq.getReturnHeatmap());
                    assertEquals("0.8", bReq.getRestrictProbability());
                    return ApiR.setData(bResp);
                });

        R<ForgeryDetectionResp> r = controller.forgeryDetection(request);
        assertEquals("200", r.getCode());
    }

    @Test
    public void toBaiduRequestNullInputTest() {
        ForgeryDetectionRequest request = null;

        when(bForgeryDetectionHandle.handle(any(BForgeryDetectionRequest.class)))
                .thenReturn(ApiR.error("你的image , url不能都为空"));

        R<ForgeryDetectionResp> r = controller.forgeryDetection(request);
        assertEquals("400", r.getCode());
    }
}
