package com.ruoyi.ccdi.project.controller;

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 org.junit.jupiter.api.Test;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;

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 CcdiProjectSpecialCheckControllerContractTest {

    @Test
    void shouldExposeFamilyAssetLiabilityListEndpointContract() throws Exception {
        Class<?> controllerClass = Class.forName("com.ruoyi.ccdi.project.controller.CcdiProjectSpecialCheckController");
        Class<?> queryDtoClass = Class.forName(
            "com.ruoyi.ccdi.project.domain.dto.CcdiProjectFamilyAssetLiabilityListQueryDTO"
        );
        RequestMapping requestMapping = controllerClass.getAnnotation(RequestMapping.class);

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

        assertNotNull(requestMapping);
        assertEquals("/ccdi/project/special-check", requestMapping.value()[0]);
        assertNotNull(getMapping);
        assertEquals("/family-asset-liability/list", getMapping.value()[0]);
        assertNotNull(operation);
        assertEquals(queryDtoClass, method.getParameterTypes()[0]);
    }

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

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

        assertNotNull(getMapping);
        assertEquals("/family-asset-liability/detail", getMapping.value()[0]);
        assertNotNull(operation);
        assertEquals(queryDtoClass, method.getParameterTypes()[0]);
    }

    @Test
    void shouldExposeFamilyAssetLiabilityDtoFields() throws Exception {
        Class<?> listDtoClass = Class.forName(
            "com.ruoyi.ccdi.project.domain.dto.CcdiProjectFamilyAssetLiabilityListQueryDTO"
        );
        Class<?> detailDtoClass = Class.forName(
            "com.ruoyi.ccdi.project.domain.dto.CcdiProjectFamilyAssetLiabilityDetailQueryDTO"
        );

        List<String> listFields = Arrays.stream(listDtoClass.getDeclaredFields())
            .map(Field::getName)
            .collect(Collectors.toList());
        List<String> detailFields = Arrays.stream(detailDtoClass.getDeclaredFields())
            .map(Field::getName)
            .collect(Collectors.toList());

        assertTrue(listFields.contains("projectId"));
        assertTrue(detailFields.contains("projectId"));
        assertTrue(detailFields.contains("staffIdCard"));
    }

    @Test
    void shouldExposeFamilyAssetLiabilityListVoFields() throws Exception {
        Class<?> itemVoClass = Class.forName(
            "com.ruoyi.ccdi.project.domain.vo.CcdiProjectFamilyAssetLiabilityListItemVO"
        );
        Class<?> listVoClass = Class.forName(
            "com.ruoyi.ccdi.project.domain.vo.CcdiProjectFamilyAssetLiabilityListVO"
        );

        List<String> itemFields = Arrays.stream(itemVoClass.getDeclaredFields())
            .map(Field::getName)
            .collect(Collectors.toList());
        List<String> listFields = Arrays.stream(listVoClass.getDeclaredFields())
            .map(Field::getName)
            .collect(Collectors.toList());

        assertTrue(itemFields.contains("staffIdCard"));
        assertTrue(itemFields.contains("staffCode"));
        assertTrue(itemFields.contains("staffName"));
        assertTrue(itemFields.contains("deptName"));
        assertTrue(itemFields.contains("totalIncome"));
        assertTrue(itemFields.contains("totalAsset"));
        assertTrue(itemFields.contains("totalDebt"));
        assertTrue(itemFields.contains("comparisonAmount"));
        assertTrue(itemFields.contains("riskLevelCode"));
        assertTrue(itemFields.contains("riskLevelName"));
        assertTrue(listFields.contains("rows"));
    }

    @Test
    void shouldExposeFamilyAssetLiabilityDetailVoFields() throws Exception {
        Class<?> detailVoClass = Class.forName(
            "com.ruoyi.ccdi.project.domain.vo.CcdiProjectFamilyAssetLiabilityDetailVO"
        );
        Class<?> incomeDetailClass = Class.forName(
            "com.ruoyi.ccdi.project.domain.vo.CcdiProjectFamilyIncomeDetailVO"
        );
        Class<?> assetDetailClass = Class.forName(
            "com.ruoyi.ccdi.project.domain.vo.CcdiProjectFamilyAssetDetailVO"
        );
        Class<?> debtDetailClass = Class.forName(
            "com.ruoyi.ccdi.project.domain.vo.CcdiProjectFamilyDebtDetailVO"
        );

        List<String> detailFields = Arrays.stream(detailVoClass.getDeclaredFields())
            .map(Field::getName)
            .collect(Collectors.toList());
        List<String> incomeFields = Arrays.stream(incomeDetailClass.getDeclaredFields())
            .map(Field::getName)
            .collect(Collectors.toList());
        List<String> assetFields = Arrays.stream(assetDetailClass.getDeclaredFields())
            .map(Field::getName)
            .collect(Collectors.toList());
        List<String> debtFields = Arrays.stream(debtDetailClass.getDeclaredFields())
            .map(Field::getName)
            .collect(Collectors.toList());

        assertTrue(detailFields.contains("incomeDetail"));
        assertTrue(detailFields.contains("assetDetail"));
        assertTrue(detailFields.contains("debtDetail"));
        assertTrue(detailFields.contains("summary"));
        assertTrue(incomeFields.contains("selfIncome"));
        assertTrue(incomeFields.contains("spouseIncome"));
        assertTrue(assetFields.contains("items"));
        assertTrue(debtFields.contains("items"));
    }
}
