package com.ecep.contract.ds.contract.service;

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.ArgumentMatchers.eq;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import java.time.LocalDate;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;

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 org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.jpa.domain.Specification;

import com.ecep.contract.ds.contract.repository.ContractRepository;
import com.ecep.contract.ds.contract.model.Contract;
import com.ecep.contract.vo.ContractVo;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;

/**
 * ContractService的测试类，用于验证实体-VO转换机制和缓存策略
 */
public class ContractServiceTest {

    @Mock
    private ContractRepository repository;

    @InjectMocks
    private ContractService service;

    private ObjectMapper objectMapper;
    private Contract mockContract;
    private ContractVo expectedVo;

    @BeforeEach
    public void setUp() {
        MockitoAnnotations.openMocks(this);
        objectMapper = new ObjectMapper();

        // 初始化测试数据
        mockContract = new Contract();
        mockContract.setId(1);
        mockContract.setName("测试合同");
        mockContract.setCode("CONTRACT-001");

        mockContract.setSetupDate(LocalDate.now());
        mockContract.setStartDate(LocalDate.now());
        mockContract.setEndDate(LocalDate.now().plusYears(1));

        expectedVo = new ContractVo();
        expectedVo.setId(1);
        expectedVo.setName("测试合同");
        expectedVo.setCode("CONTRACT-001");
        expectedVo.setSetupDate(mockContract.getSetupDate());
        expectedVo.setStartDate(mockContract.getStartDate());
        expectedVo.setEndDate(mockContract.getEndDate());
    }

    /**
     * 测试findById方法，验证实体-VO转换
     */
    @Test
    public void testFindById() {
        // 配置mock行为
        when(repository.findById(1)).thenReturn(Optional.of(mockContract));

        // 执行方法
        ContractVo result = service.findById(1);

        // 验证结果
        assertNotNull(result);
        assertEquals(expectedVo.getId(), result.getId());
        assertEquals(expectedVo.getName(), result.getName());
        assertEquals(expectedVo.getCode(), result.getCode());

        // 验证方法调用
        verify(repository, times(1)).findById(1);
    }

    /**
     * 测试findById方法，验证当实体不存在时返回null
     */
    @Test
    public void testFindById_EntityNotFound() {
        // 配置mock行为
        when(repository.findById(999)).thenReturn(Optional.empty());

        // 执行方法
        ContractVo result = service.findById(999);

        // 验证结果
        assertNull(result);

        // 验证方法调用
        verify(repository, times(1)).findById(999);
    }

    /**
     * 测试save方法，验证保存逻辑
     */
    @Test
    public void testSave() {
        // 配置mock行为
        when(repository.save(any(Contract.class))).thenReturn(mockContract);

        // 执行方法
        Contract result = service.save(mockContract);

        // 验证结果
        assertNotNull(result);
        assertEquals(mockContract.getId(), result.getId());

        // 验证方法调用
        verify(repository, times(1)).save(mockContract);
    }

    /**
     * 测试delete方法，验证删除逻辑
     */
    @Test
    public void testDelete() {
        // 执行方法
        service.delete(mockContract);

        // 验证方法调用
        verify(repository, times(1)).delete(mockContract);
    }

    /**
     * 测试findAll方法，验证分页和转换功能
     */
    @Test
    public void testFindAll() {
        // 准备测试数据
        List<Contract> contracts = Arrays.asList(mockContract);
        Page<Contract> contractPage = new PageImpl<>(contracts);
        PageRequest pageRequest = PageRequest.of(0, 10);

        // 配置mock行为
        when(repository.findAll(pageRequest)).thenReturn(contractPage);

        // 执行方法
        Page<ContractVo> result = service.findAll((JsonNode) null, pageRequest);

        // 验证结果
        assertNotNull(result);
        assertEquals(1, result.getTotalElements());
        assertEquals(expectedVo.getId(), result.getContent().get(0).getId());

        // 验证方法调用
        verify(repository, times(1)).findAll(pageRequest);
    }

    /**
     * 测试带参数的findAll方法，验证参数处理和转换功能
     */
    @Test
    public void testFindAll_WithParams() throws Exception {
        // 准备测试数据
        List<Contract> contracts = Arrays.asList(mockContract);
        Page<Contract> contractPage = new PageImpl<>(contracts);
        PageRequest pageRequest = PageRequest.of(0, 10);
        String paramsJson = "{\"searchText\": \"测试\"}";
        JsonNode paramsNode = objectMapper.readTree(paramsJson);

        // 配置mock行为
        when(repository.findAll(any(Specification.class), eq(pageRequest))).thenReturn(contractPage);

        // 执行方法
        Page<ContractVo> result = service.findAll(paramsNode, pageRequest);

        // 验证结果
        assertNotNull(result);
        assertEquals(1, result.getTotalElements());

        // 验证方法调用
        verify(repository, times(1)).findAll(any(Specification.class), eq(pageRequest));
    }
}