package com.ycwl.basic.pricing.service;

import com.ycwl.basic.pricing.dto.VoucherInfo;
import com.ycwl.basic.pricing.dto.req.VoucherBatchCreateReqV2;
import com.ycwl.basic.pricing.entity.PriceVoucherBatchConfig;
import com.ycwl.basic.pricing.enums.ProductType;
import com.ycwl.basic.pricing.enums.VoucherDiscountType;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;

import java.math.BigDecimal;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;

import static org.junit.jupiter.api.Assertions.*;

/**
 * 券码时间范围功能单元测试
 */
public class VoucherTimeRangeTest {
    
    private Long testScenicId = 1001L;
    private Long testBrokerId = 2001L;
    
    @BeforeEach
    void setUp() {
    }

    @Test
    @DisplayName("测试券码批次时间范围验证 - 正常时间范围")
    void testValidTimeRange() {
        // 创建时间范围：当前时间前1小时到后1小时
        Calendar cal = Calendar.getInstance();
        cal.add(Calendar.HOUR_OF_DAY, -1);
        Date validStartTime = cal.getTime();
        
        cal = Calendar.getInstance();
        cal.add(Calendar.HOUR_OF_DAY, 1);
        Date validEndTime = cal.getTime();
        
        PriceVoucherBatchConfig batchConfig = createTestBatchConfig(validStartTime, validEndTime);
        
        // 测试当前时间在有效期内
        assertTrue(batchConfig.isWithinValidTimeRange(), "当前时间应该在有效期内");
        
        // 测试指定时间在有效期内
        assertTrue(batchConfig.isWithinValidTimeRange(new Date()), "指定时间应该在有效期内");
    }

    @Test
    @DisplayName("测试券码批次时间范围验证 - 尚未生效")
    void testTimeRangeNotYetValid() {
        // 创建时间范围：未来1小时到未来2小时
        Calendar cal = Calendar.getInstance();
        cal.add(Calendar.HOUR_OF_DAY, 1);
        Date validStartTime = cal.getTime();
        
        cal = Calendar.getInstance();
        cal.add(Calendar.HOUR_OF_DAY, 2);
        Date validEndTime = cal.getTime();
        
        PriceVoucherBatchConfig batchConfig = createTestBatchConfig(validStartTime, validEndTime);
        
        // 测试当前时间不在有效期内（尚未生效）
        assertFalse(batchConfig.isWithinValidTimeRange(), "当前时间不应该在有效期内（尚未生效）");
    }

    @Test
    @DisplayName("测试券码批次时间范围验证 - 已过期")
    void testTimeRangeExpired() {
        // 创建时间范围：过去2小时到过去1小时
        Calendar cal = Calendar.getInstance();
        cal.add(Calendar.HOUR_OF_DAY, -2);
        Date validStartTime = cal.getTime();
        
        cal = Calendar.getInstance();
        cal.add(Calendar.HOUR_OF_DAY, -1);
        Date validEndTime = cal.getTime();
        
        PriceVoucherBatchConfig batchConfig = createTestBatchConfig(validStartTime, validEndTime);
        
        // 测试当前时间不在有效期内（已过期）
        assertFalse(batchConfig.isWithinValidTimeRange(), "当前时间不应该在有效期内（已过期）");
    }

    @Test
    @DisplayName("测试券码批次时间范围验证 - 无时间限制")
    void testNoTimeRestriction() {
        // 创建无时间限制的批次配置
        PriceVoucherBatchConfig batchConfig = createTestBatchConfig(null, null);
        
        // 测试无时间限制时应该总是有效
        assertTrue(batchConfig.isWithinValidTimeRange(), "无时间限制的券码应该总是有效");
    }

    @Test
    @DisplayName("测试券码批次时间范围验证 - 只有开始时间")
    void testOnlyStartTime() {
        // 创建只有开始时间的批次配置（过去1小时开始，无结束时间）
        Calendar cal = Calendar.getInstance();
        cal.add(Calendar.HOUR_OF_DAY, -1);
        Date validStartTime = cal.getTime();
        
        PriceVoucherBatchConfig batchConfig = createTestBatchConfig(validStartTime, null);
        
        // 测试应该有效（已过开始时间且无结束时间限制）
        assertTrue(batchConfig.isWithinValidTimeRange(), "只有开始时间的券码在开始时间后应该有效");
    }

    @Test
    @DisplayName("测试券码批次时间范围验证 - 只有结束时间")
    void testOnlyEndTime() {
        // 创建只有结束时间的批次配置（无开始时间，1小时后结束）
        Calendar cal = Calendar.getInstance();
        cal.add(Calendar.HOUR_OF_DAY, 1);
        Date validEndTime = cal.getTime();
        
        PriceVoucherBatchConfig batchConfig = createTestBatchConfig(null, validEndTime);
        
        // 测试应该有效（无开始时间限制且未到结束时间）
        assertTrue(batchConfig.isWithinValidTimeRange(), "只有结束时间的券码在结束时间前应该有效");
    }

    @Test
    @DisplayName("测试VoucherInfo时间范围方法")
    void testVoucherInfoTimeRangeMethods() {
        Calendar cal = Calendar.getInstance();
        cal.add(Calendar.HOUR_OF_DAY, -1);
        Date validStartTime = cal.getTime();
        
        cal = Calendar.getInstance();
        cal.add(Calendar.HOUR_OF_DAY, 1);
        Date validEndTime = cal.getTime();
        
        VoucherInfo voucherInfo = new VoucherInfo();
        voucherInfo.setValidStartTime(validStartTime);
        voucherInfo.setValidEndTime(validEndTime);
        
        // 测试当前时间在有效期内
        assertTrue(voucherInfo.isWithinValidTimeRange(), "VoucherInfo当前时间应该在有效期内");
        
        // 测试指定时间在有效期内
        assertTrue(voucherInfo.isWithinValidTimeRange(new Date()), "VoucherInfo指定时间应该在有效期内");
        
        // 测试过期时间
        cal = Calendar.getInstance();
        cal.add(Calendar.HOUR_OF_DAY, 2);
        Date futureTime = cal.getTime();
        assertFalse(voucherInfo.isWithinValidTimeRange(futureTime), "VoucherInfo未来时间不应该在有效期内");
    }

    @Test
    @DisplayName("测试批次创建请求时间范围验证")
    void testBatchCreateRequestTimeValidation() {
        VoucherBatchCreateReqV2 request = new VoucherBatchCreateReqV2();
        request.setBatchName("时间范围测试批次");
        request.setScenicId(testScenicId);
        request.setBrokerId(testBrokerId);
        request.setDiscountType(VoucherDiscountType.DISCOUNT.getCode());
        request.setDiscountValue(new BigDecimal("10.00"));
        request.setTotalCount(100);
        request.setApplicableProducts(Arrays.asList(ProductType.VLOG_VIDEO, ProductType.PHOTO_SET));
        
        // 测试正常时间范围
        Calendar cal = Calendar.getInstance();
        Date validStartTime = cal.getTime();
        cal.add(Calendar.HOUR_OF_DAY, 24);
        Date validEndTime = cal.getTime();
        
        request.setValidStartTime(validStartTime);
        request.setValidEndTime(validEndTime);
        
        // 这里应该调用实际的批次创建服务进行验证
        // 正常情况下不应该抛出异常
        assertDoesNotThrow(() -> {
            validateTimeRange(request.getValidStartTime(), request.getValidEndTime());
        }, "正常时间范围不应该抛出异常");
        
        // 测试无效时间范围（开始时间晚于结束时间）
        request.setValidStartTime(validEndTime);  // 交换开始和结束时间
        request.setValidEndTime(validStartTime);
        
        // 应该抛出验证异常
        assertThrows(IllegalArgumentException.class, () -> {
            validateTimeRange(request.getValidStartTime(), request.getValidEndTime());
        }, "无效时间范围应该抛出异常");
    }

    @Test
    @DisplayName("测试边界条件 - 开始时间等于结束时间")
    void testBoundaryCondition_StartEqualsEnd() {
        Date sameTime = new Date();
        
        PriceVoucherBatchConfig batchConfig = createTestBatchConfig(sameTime, sameTime);
        
        // 测试开始时间等于结束时间时的行为
        assertTrue(batchConfig.isWithinValidTimeRange(sameTime), 
            "开始时间等于结束时间时，该时间点应该被认为是有效的");
    }

    // 辅助方法：创建测试用的批次配置
    private PriceVoucherBatchConfig createTestBatchConfig(Date validStartTime, Date validEndTime) {
        PriceVoucherBatchConfig config = new PriceVoucherBatchConfig();
        config.setId(1L);
        config.setBatchName("测试批次");
        config.setScenicId(testScenicId);
        config.setBrokerId(testBrokerId);
        config.setDiscountType(VoucherDiscountType.DISCOUNT.getCode());
        config.setDiscountValue(new BigDecimal("10.00"));
        config.setTotalCount(100);
        config.setUsedCount(0);
        config.setClaimedCount(0);
        config.setStatus(1);
        config.setValidStartTime(validStartTime);
        config.setValidEndTime(validEndTime);
        config.setDeleted(0);
        config.setCreateTime(new Date());
        
        return config;
    }
    
    // 辅助方法：验证时间范围
    private void validateTimeRange(Date validStartTime, Date validEndTime) {
        if (validStartTime != null && validEndTime != null) {
            if (validStartTime.after(validEndTime)) {
                throw new IllegalArgumentException("有效期开始时间不能晚于结束时间");
            }
        }
    }
}
