package com.ecep.contract.ds.sale.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.LocalDateTime;
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.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;

import com.ecep.contract.ds.contract.repository.SalesBillVoucherRepository;
import com.ecep.contract.ds.contract.service.SalesBillVoucherService;
import com.ecep.contract.ds.customer.model.SalesBillVoucher;
import com.ecep.contract.vo.SalesBillVoucherVo;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;

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

    @Mock
    private SalesBillVoucherRepository repository;

    @InjectMocks
    private SalesBillVoucherService service;

    private ObjectMapper objectMapper;
    private SalesBillVoucher mockBillVoucher;
    private SalesBillVoucherVo expectedVo;

    @BeforeEach
    public void setUp() {
        MockitoAnnotations.openMocks(this);
        objectMapper = new ObjectMapper();
        
        // 初始化测试数据
        mockBillVoucher = new SalesBillVoucher();
        mockBillVoucher.setId(1); // 使用Integer类型而不是long
        mockBillVoucher.setCode("SBV-TEST001");
        mockBillVoucher.setMakerDate(LocalDateTime.now());
        
        expectedVo = new SalesBillVoucherVo();
        expectedVo.setId(1); // 使用Integer类型而不是long
        expectedVo.setCode("SBV-TEST001");
        expectedVo.setMakerDate(mockBillVoucher.getMakerDate());
    }

    /**
     * 测试findById方法，验证实体-VO转换
     */
    @Test
    public void testFindById() {
        // 配置mock行为
        when(repository.findById(1)).thenReturn(Optional.of(mockBillVoucher));
        
        // 执行方法
        SalesBillVoucherVo result = service.findById(1);
        
        // 验证结果
        assertNotNull(result);
        assertEquals(expectedVo.getId(), result.getId());
        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());
        
        // 执行方法
        SalesBillVoucherVo result = service.findById(999);
        
        // 验证结果
        assertNull(result);
        
        // 验证方法调用
        verify(repository, times(1)).findById(999);
    }

    /**
     * 测试save方法，验证保存逻辑
     */
    @Test
    public void testSave() {
        // 配置mock行为
        when(repository.save(any(SalesBillVoucher.class))).thenReturn(mockBillVoucher);
        
        // 执行方法
        SalesBillVoucher result = service.save(mockBillVoucher);
        
        // 验证结果
        assertNotNull(result);
        assertEquals(mockBillVoucher.getId(), result.getId());
        
        // 验证方法调用
        verify(repository, times(1)).save(mockBillVoucher);
    }

    /**
     * 测试delete方法，验证删除逻辑
     */
    @Test
    public void testDelete() {
        // 执行方法
        service.delete(mockBillVoucher);
        
        // 验证方法调用
        verify(repository, times(1)).delete(mockBillVoucher);
    }

    /**
     * 测试findAll方法，验证分页功能
     */
    @Test
    public void testFindAll() {
        // 准备测试数据
        List<SalesBillVoucher> salesBillVouchers = Arrays.asList(mockBillVoucher);
        Pageable pageable = PageRequest.of(0, 10);
        Page<SalesBillVoucher> pageResult = new PageImpl<>(salesBillVouchers, pageable, salesBillVouchers.size());

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

        // 执行方法 - 使用空的JsonNode而不是null，避免空指针异常
        JsonNode emptyParamsNode = objectMapper.createObjectNode();
        Page<SalesBillVoucherVo> result = service.findAll(emptyParamsNode, pageable);

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

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

    /**
     * 测试带参数的findAll方法，验证参数处理
     */
    @Test
    public void testFindAll_WithParams() throws Exception {
        // 准备测试数据
        List<SalesBillVoucher> vouchers = Arrays.asList(mockBillVoucher);
        PageRequest pageable = PageRequest.of(0, 10); // 使用PageRequest.of而不是Pageable.ofSize
        Page<SalesBillVoucher> pageResult = new PageImpl<>(vouchers, pageable, vouchers.size());
        
        // 创建带搜索参数的JSON
        String paramsJson = "{\"searchText\": \"测试\"}";
        JsonNode paramsNode = objectMapper.readTree(paramsJson);
        
        // 配置mock行为
        when(repository.findAll(any(Specification.class), eq(pageable))).thenReturn(pageResult);
        
        // 执行方法
        Page<SalesBillVoucherVo> result = service.findAll(paramsNode, pageable);
        
        // 验证结果
        assertNotNull(result);
        assertEquals(1, result.getTotalElements());
        
        // 验证方法调用
        verify(repository, times(1)).findAll(any(Specification.class), eq(pageable));
    }

    /**
     * 测试refId参数处理，验证关联查询功能
     */
    @Test
    public void testFindByRefId() throws Exception {
        // 设置一个引用ID
        Integer refId = 1001;
        mockBillVoucher.setRefId(refId);
        
        // 准备测试数据
        List<SalesBillVoucher> vouchers = Arrays.asList(mockBillVoucher);
        PageRequest pageable = PageRequest.of(0, 10); // 使用PageRequest.of而不是Pageable.ofSize
        Page<SalesBillVoucher> pageResult = new PageImpl<>(vouchers, pageable, vouchers.size());
        
        // 创建带refId参数的JSON
        String paramsJson = String.format("{\"refId\": %d}", refId);
        JsonNode paramsNode = objectMapper.readTree(paramsJson);
        
        // 配置mock行为
        when(repository.findAll(any(Specification.class), eq(pageable))).thenReturn(pageResult);
        
        // 执行方法
        Page<SalesBillVoucherVo> result = service.findAll(paramsNode, pageable);
        
        // 验证结果
        assertNotNull(result);
        assertEquals(1, result.getTotalElements());
        
        // 验证方法调用
        verify(repository, times(1)).findAll(any(Specification.class), eq(pageable));
    }
}