package com.ruoyi.ccdi.project.controller;

import com.ruoyi.common.core.domain.AjaxResult;
import io.swagger.v3.oas.annotations.Operation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import jakarta.servlet.http.HttpServletResponse;
import org.junit.jupiter.api.Test;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;

class CcdiProjectOverviewControllerContractTest {

    @Test
    void shouldExposeRiskModelCardsEndpointContract() throws Exception {
        Class<?> controllerClass = Class.forName("com.ruoyi.ccdi.project.controller.CcdiProjectOverviewController");
        RequestMapping requestMapping = controllerClass.getAnnotation(RequestMapping.class);

        Method method = controllerClass.getMethod("getRiskModelCards", Long.class);
        GetMapping getMapping = method.getAnnotation(GetMapping.class);
        Operation operation = method.getAnnotation(Operation.class);

        assertNotNull(requestMapping);
        assertEquals("/ccdi/project/overview", requestMapping.value()[0]);
        assertNotNull(getMapping);
        assertEquals("/risk-models/cards", getMapping.value()[0]);
        assertNotNull(operation);
    }

    @Test
    void shouldExposeRiskModelPeopleEndpointContract() throws Exception {
        Class<?> controllerClass = Class.forName("com.ruoyi.ccdi.project.controller.CcdiProjectOverviewController");
        Class<?> queryDtoClass = Class.forName("com.ruoyi.ccdi.project.domain.dto.CcdiProjectRiskModelPeopleQueryDTO");

        Method method = controllerClass.getMethod("getRiskModelPeople", queryDtoClass);
        GetMapping getMapping = method.getAnnotation(GetMapping.class);
        Operation operation = method.getAnnotation(Operation.class);

        assertNotNull(getMapping);
        assertEquals("/risk-models/people", getMapping.value()[0]);
        assertNotNull(operation);
        assertEquals(queryDtoClass, method.getParameterTypes()[0]);
    }

    @Test
    void shouldExposeRiskModelPeopleQueryDtoFields() throws Exception {
        Class<?> dtoClass = Class.forName("com.ruoyi.ccdi.project.domain.dto.CcdiProjectRiskModelPeopleQueryDTO");

        List<String> fieldNames = Arrays.stream(dtoClass.getDeclaredFields())
            .map(Field::getName)
            .collect(Collectors.toList());

        assertTrue(fieldNames.contains("projectId"));
        assertTrue(fieldNames.contains("modelCodes"));
        assertTrue(fieldNames.contains("matchMode"));
        assertTrue(fieldNames.contains("keyword"));
        assertTrue(fieldNames.contains("deptId"));
        assertTrue(fieldNames.contains("pageNum"));
        assertTrue(fieldNames.contains("pageSize"));
    }

    @Test
    void shouldExposePersonAnalysisDetailEndpointContract() throws Exception {
        Class<?> controllerClass = Class.forName("com.ruoyi.ccdi.project.controller.CcdiProjectOverviewController");
        Class<?> queryDtoClass =
            Class.forName("com.ruoyi.ccdi.project.domain.dto.CcdiProjectPersonAnalysisDetailQueryDTO");
        Method method = controllerClass.getMethod("getPersonAnalysisDetail", queryDtoClass);
        GetMapping getMapping = method.getAnnotation(GetMapping.class);
        Operation operation = method.getAnnotation(Operation.class);

        assertNotNull(getMapping);
        assertEquals("/person-analysis/detail", getMapping.value()[0]);
        assertNotNull(operation);
        assertEquals(queryDtoClass, method.getParameterTypes()[0]);
        assertEquals(AjaxResult.class, method.getReturnType());
    }

    @Test
    void shouldExposePersonAnalysisDetailQueryDtoFields() throws Exception {
        Class<?> dtoClass = Class.forName("com.ruoyi.ccdi.project.domain.dto.CcdiProjectPersonAnalysisDetailQueryDTO");

        List<String> fieldNames = Arrays.stream(dtoClass.getDeclaredFields())
            .map(Field::getName)
            .collect(Collectors.toList());

        assertEquals(List.of("projectId", "staffIdCard"), fieldNames);
    }

    @Test
    void shouldExposeSuspiciousTransactionsEndpointContract() throws Exception {
        Class<?> controllerClass = Class.forName("com.ruoyi.ccdi.project.controller.CcdiProjectOverviewController");
        Class<?> queryDtoClass =
            Class.forName("com.ruoyi.ccdi.project.domain.dto.CcdiProjectSuspiciousTransactionQueryDTO");
        Method method = controllerClass.getMethod("getSuspiciousTransactions", queryDtoClass);
        GetMapping getMapping = method.getAnnotation(GetMapping.class);
        Operation operation = method.getAnnotation(Operation.class);

        assertNotNull(getMapping);
        assertEquals("/suspicious-transactions", getMapping.value()[0]);
        assertNotNull(operation);
        assertEquals(queryDtoClass, method.getParameterTypes()[0]);
        assertEquals(AjaxResult.class, method.getReturnType());
    }

    @Test
    void shouldExposeEmployeeCreditNegativeEndpointContract() throws Exception {
        Class<?> controllerClass = Class.forName("com.ruoyi.ccdi.project.controller.CcdiProjectOverviewController");
        Class<?> queryDtoClass =
            Class.forName("com.ruoyi.ccdi.project.domain.dto.CcdiProjectEmployeeCreditNegativeQueryDTO");
        Method method = controllerClass.getMethod("getEmployeeCreditNegative", queryDtoClass);
        GetMapping getMapping = method.getAnnotation(GetMapping.class);
        Operation operation = method.getAnnotation(Operation.class);

        assertNotNull(getMapping);
        assertEquals("/employee-credit-negative", getMapping.value()[0]);
        assertNotNull(operation);
        assertEquals(queryDtoClass, method.getParameterTypes()[0]);
        assertEquals(AjaxResult.class, method.getReturnType());
    }

    @Test
    void shouldExposeAbnormalAccountPeopleEndpointContract() throws Exception {
        Class<?> controllerClass = Class.forName("com.ruoyi.ccdi.project.controller.CcdiProjectOverviewController");
        Class<?> queryDtoClass =
            Class.forName("com.ruoyi.ccdi.project.domain.dto.CcdiProjectAbnormalAccountQueryDTO");

        Method method = controllerClass.getMethod("getAbnormalAccountPeople", queryDtoClass);
        GetMapping getMapping = method.getAnnotation(GetMapping.class);
        Operation operation = method.getAnnotation(Operation.class);
        PreAuthorize preAuthorize = method.getAnnotation(PreAuthorize.class);

        assertNotNull(getMapping);
        assertEquals("/abnormal-account-people", getMapping.value()[0]);
        assertNotNull(operation);
        assertEquals("查询异常账户人员信息", operation.summary());
        assertNotNull(preAuthorize);
        assertEquals("@ss.hasPermi('ccdi:project:query')", preAuthorize.value());
        assertEquals(queryDtoClass, method.getParameterTypes()[0]);
    }

    @Test
    void shouldExposeSuspiciousTransactionsExportEndpointContract() throws Exception {
        Class<?> controllerClass = Class.forName("com.ruoyi.ccdi.project.controller.CcdiProjectOverviewController");
        Class<?> queryDtoClass =
            Class.forName("com.ruoyi.ccdi.project.domain.dto.CcdiProjectSuspiciousTransactionQueryDTO");
        Method method = controllerClass.getMethod(
            "exportSuspiciousTransactions",
            HttpServletResponse.class,
            queryDtoClass
        );
        PostMapping postMapping = method.getAnnotation(PostMapping.class);
        Operation operation = method.getAnnotation(Operation.class);

        assertNotNull(postMapping);
        assertEquals("/suspicious-transactions/export", postMapping.value()[0]);
        assertNotNull(operation);
    }

    @Test
    void shouldExposeRiskDetailsExportEndpointContract() throws Exception {
        Class<?> controllerClass = Class.forName("com.ruoyi.ccdi.project.controller.CcdiProjectOverviewController");
        Method method = controllerClass.getMethod(
            "exportRiskDetails",
            HttpServletResponse.class,
            Class.forName("com.ruoyi.ccdi.project.domain.dto.CcdiProjectSuspiciousTransactionQueryDTO")
        );
        PostMapping postMapping = method.getAnnotation(PostMapping.class);
        Operation operation = method.getAnnotation(Operation.class);

        assertNotNull(postMapping);
        assertEquals("/risk-details/export", postMapping.value()[0]);
        assertNotNull(operation);
    }

    @Test
    void shouldExposeOverviewReportExportEndpointContract() throws Exception {
        Class<?> controllerClass = Class.forName("com.ruoyi.ccdi.project.controller.CcdiProjectOverviewController");
        Method method = controllerClass.getMethod(
            "exportOverviewReport",
            HttpServletResponse.class,
            Long.class
        );
        RequestMapping requestMapping = method.getAnnotation(RequestMapping.class);
        Operation operation = method.getAnnotation(Operation.class);
        PreAuthorize preAuthorize = method.getAnnotation(PreAuthorize.class);

        assertNotNull(requestMapping);
        assertEquals("/report/export", requestMapping.value()[0]);
        assertEquals(List.of(RequestMethod.GET, RequestMethod.POST), Arrays.asList(requestMapping.method()));
        assertNotNull(operation);
        assertEquals("导出结果总览报告", operation.summary());
        assertNotNull(preAuthorize);
        assertEquals("@ss.hasPermi('ccdi:project:query')", preAuthorize.value());
    }

    @Test
    void shouldExposeSuspiciousTransactionsQueryDtoFields() throws Exception {
        Class<?> dtoClass = Class.forName("com.ruoyi.ccdi.project.domain.dto.CcdiProjectSuspiciousTransactionQueryDTO");

        List<String> fieldNames = Arrays.stream(dtoClass.getDeclaredFields())
            .map(Field::getName)
            .collect(Collectors.toList());

        assertEquals(
            List.of("projectId", "modelCode", "suspiciousType", "pageNum", "pageSize", "includeExternalPerson"),
            fieldNames
        );
    }

    @Test
    void shouldExposeEmployeeCreditNegativeQueryDtoFields() throws Exception {
        Class<?> dtoClass = Class.forName("com.ruoyi.ccdi.project.domain.dto.CcdiProjectEmployeeCreditNegativeQueryDTO");

        List<String> fieldNames = Arrays.stream(dtoClass.getDeclaredFields())
            .map(Field::getName)
            .collect(Collectors.toList());

        assertEquals(List.of("projectId", "pageNum", "pageSize"), fieldNames);
    }
}
