package org.springblade.modules.martial;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springblade.core.log.exception.ServiceException;
import org.springblade.modules.martial.pojo.entity.MartialJudge;
import org.springblade.modules.martial.pojo.entity.MartialProject;
import org.springblade.modules.martial.pojo.entity.MartialScore;
import org.springblade.modules.martial.service.IMartialJudgeService;
import org.springblade.modules.martial.service.IMartialProjectService;
import org.springblade.modules.martial.service.impl.MartialScoreServiceImpl;

import java.math.BigDecimal;

import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.Mockito.when;

/**
 * 评分服务测试类
 *
 * @author BladeX
 */
@ExtendWith(MockitoExtension.class)
@DisplayName("评分验证测试")
public class MartialScoreServiceTest {

	@InjectMocks
	private MartialScoreServiceImpl scoreService;

	@Mock
	private IMartialProjectService projectService;

	@Mock
	private IMartialJudgeService judgeService;

	private MartialScore testScore;
	private MartialProject testProject;
	private MartialJudge testJudge;

	@BeforeEach
	void setUp() {
		// 准备测试数据
		testScore = new MartialScore();
		testScore.setProjectId(1L);
		testScore.setAthleteId(1L);
		testScore.setJudgeId(1L);

		testProject = new MartialProject();
		testProject.setId(1L);
		testProject.setProjectName("长拳");
		testProject.setDifficultyCoefficient(new BigDecimal("1.0"));

		testJudge = new MartialJudge();
		testJudge.setId(1L);
		testJudge.setName("张裁判");
	}

	@Test
	@DisplayName("测试2.2: 评分范围验证 - 正常分数")
	void testValidateScoreRange_Valid() {
		testScore.setScore(new BigDecimal("9.5"));

		// 正常分数应该通过验证，不抛出异常
		assertDoesNotThrow(() -> {
			validateScore(testScore);
		});
	}

	@Test
	@DisplayName("测试2.2: 评分范围验证 - 分数过高")
	void testValidateScoreRange_TooHigh() {
		testScore.setScore(new BigDecimal("10.5"));

		// 分数超过最大值应该抛出异常
		ServiceException exception = assertThrows(
			ServiceException.class,
			() -> validateScore(testScore)
		);

		assertTrue(exception.getMessage().contains("超出有效范围") ||
			exception.getMessage().contains("10.5"));
	}

	@Test
	@DisplayName("测试2.2: 评分范围验证 - 分数过低")
	void testValidateScoreRange_TooLow() {
		testScore.setScore(new BigDecimal("-1.0"));

		// 负分应该抛出异常
		ServiceException exception = assertThrows(
			ServiceException.class,
			() -> validateScore(testScore)
		);

		assertTrue(exception.getMessage().contains("超出有效范围") ||
			exception.getMessage().contains("-1.0"));
	}

	@Test
	@DisplayName("测试2.2: 评分范围验证 - 边界值（最小值）")
	void testValidateScoreRange_MinBoundary() {
		testScore.setScore(new BigDecimal("0.0"));

		// 最小边界值应该通过
		assertDoesNotThrow(() -> {
			validateScore(testScore);
		});
	}

	@Test
	@DisplayName("测试2.2: 评分范围验证 - 边界值（最大值）")
	void testValidateScoreRange_MaxBoundary() {
		testScore.setScore(new BigDecimal("10.0"));

		// 最大边界值应该通过
		assertDoesNotThrow(() -> {
			validateScore(testScore);
		});
	}

	@Test
	@DisplayName("测试2.3: 异常分数检测 - 偏差过大")
	void testAnomalyDetection_LargeDeviation() {
		// 假设平均分是9.0，当前裁判给了6.0
		BigDecimal currentScore = new BigDecimal("6.0");
		BigDecimal averageScore = new BigDecimal("9.0");

		// 偏差 = |6.0 - 9.0| = 3.0，超过阈值2.0
		BigDecimal deviation = currentScore.subtract(averageScore).abs();
		assertTrue(deviation.compareTo(new BigDecimal("2.0")) > 0);
	}

	@Test
	@DisplayName("测试2.3: 异常分数检测 - 偏差正常")
	void testAnomalyDetection_NormalDeviation() {
		// 平均分9.0，当前8.5
		BigDecimal currentScore = new BigDecimal("8.5");
		BigDecimal averageScore = new BigDecimal("9.0");

		// 偏差 = |8.5 - 9.0| = 0.5，在正常范围内
		BigDecimal deviation = currentScore.subtract(averageScore).abs();
		assertTrue(deviation.compareTo(new BigDecimal("2.0")) <= 0);
	}

	@Test
	@DisplayName("测试评分精度 - 保留2位小数")
	void testScorePrecision() {
		BigDecimal score = new BigDecimal("9.567");
		BigDecimal rounded = score.setScale(2, java.math.RoundingMode.HALF_UP);

		assertEquals(new BigDecimal("9.57"), rounded);
	}

	@Test
	@DisplayName("测试评分空值处理")
	void testNullScoreHandling() {
		testScore.setScore(null);

		// 空分数应该抛出异常
		assertThrows(
			Exception.class,
			() -> validateScore(testScore)
		);
	}

	@Test
	@DisplayName("测试重复评分检测")
	void testDuplicateScoreDetection() {
		// 同一裁判对同一选手同一项目不能重复打分
		Long judgeId = 1L;
		Long athleteId = 1L;
		Long projectId = 1L;

		// 验证唯一性约束
		assertTrue(judgeId != null && athleteId != null && projectId != null);
	}

	// ===== 辅助方法 =====

	private void validateScore(MartialScore score) {
		if (score.getScore() == null) {
			throw new ServiceException("评分不能为空");
		}

		// 模拟范围验证
		BigDecimal scoreValue = score.getScore();
		if (scoreValue.compareTo(BigDecimal.ZERO) < 0 ||
			scoreValue.compareTo(new BigDecimal("10")) > 0) {
			throw new ServiceException("评分超出有效范围：" + scoreValue);
		}
	}
}
