package org.springblade.modules.martial;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
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.excel.AthleteExportExcel;
import org.springblade.modules.martial.mapper.MartialAthleteMapper;
import org.springblade.modules.martial.pojo.entity.MartialAthlete;
import org.springblade.modules.martial.service.impl.MartialAthleteServiceImpl;

import java.util.ArrayList;
import java.util.List;

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

/**
 * 运动员服务测试类
 *
 * @author BladeX
 */
@ExtendWith(MockitoExtension.class)
@DisplayName("运动员管理测试")
public class MartialAthleteServiceTest {

	@InjectMocks
	private MartialAthleteServiceImpl athleteService;

	@Mock
	private MartialAthleteMapper athleteMapper;

	private MartialAthlete testAthlete;
	private List<MartialAthlete> mockAthletes;

	@BeforeEach
	void setUp() {
		// 准备测试数据
		testAthlete = new MartialAthlete();
		testAthlete.setId(1L);
		testAthlete.setPlayerNo("A001");
		testAthlete.setPlayerName("张三");
		testAthlete.setGender(1); // 男
		testAthlete.setAge(25);
		testAthlete.setTeamName("北京队");
		testAthlete.setContactPhone("13800138000");
		testAthlete.setCategory("长拳");
		testAthlete.setCompetitionStatus(0); // 待出场
		testAthlete.setCompetitionId(1L);

		// 准备列表数据
		mockAthletes = new ArrayList<>();
		mockAthletes.add(testAthlete);
	}

	@Test
	@DisplayName("测试2.1: 运动员签到 - 正常签到")
	void testCheckIn_Normal() {
		// 初始状态为待出场
		testAthlete.setCompetitionStatus(0);
		assertEquals(0, testAthlete.getCompetitionStatus());

		// 模拟签到操作：状态变为进行中
		testAthlete.setCompetitionStatus(1);

		// 验证状态已更新
		assertEquals(1, testAthlete.getCompetitionStatus());
	}

	@Test
	@DisplayName("测试2.1: 运动员签到 - 重复签到检测")
	void testCheckIn_AlreadyCheckedIn() {
		testAthlete.setCompetitionStatus(1); // 已签到

		// 验证已签到状态
		assertEquals(1, testAthlete.getCompetitionStatus());

		// 尝试再次签到应该检测到已签到
		assertNotEquals(0, testAthlete.getCompetitionStatus());
	}

	@Test
	@DisplayName("测试比赛状态流转 - 完整流程")
	void testCompetitionStatusFlow() {
		// 状态流转：0(待出场) -> 1(进行中) -> 2(已完成)

		// 初始：待出场
		testAthlete.setCompetitionStatus(0);
		assertEquals(0, testAthlete.getCompetitionStatus());

		// 签到：进行中
		testAthlete.setCompetitionStatus(1);
		assertEquals(1, testAthlete.getCompetitionStatus());

		// 完成：已完成
		testAthlete.setCompetitionStatus(2);
		assertEquals(2, testAthlete.getCompetitionStatus());
	}

	@Test
	@DisplayName("测试比赛状态验证 - 无效状态拒绝")
	void testInvalidCompetitionStatus() {
		// 测试无效状态值（超出0-2范围）
		Integer invalidStatus = 99;

		// 验证状态值范围
		assertTrue(invalidStatus < 0 || invalidStatus > 2);
	}

	@Test
	@DisplayName("测试性别转换 - 男性")
	void testGenderConversion_Male() {
		testAthlete.setGender(1);

		String genderStr = testAthlete.getGender() == 1 ? "男" : "女";
		assertEquals("男", genderStr);
	}

	@Test
	@DisplayName("测试性别转换 - 女性")
	void testGenderConversion_Female() {
		testAthlete.setGender(2);

		String genderStr = testAthlete.getGender() == 2 ? "女" : "男";
		assertEquals("女", genderStr);
	}

	@Test
	@DisplayName("测试运动员编号唯一性")
	void testPlayerNoUniqueness() {
		String playerNo = "A001";

		// 验证编号不为空
		assertNotNull(playerNo);
		assertFalse(playerNo.isEmpty());

		// 验证编号格式（字母+数字）
		assertTrue(playerNo.matches("[A-Z]\\d{3}"));
	}

	@Test
	@DisplayName("测试联系方式验证")
	void testContactPhoneValidation() {
		String validPhone = "13800138000";
		String invalidPhone = "12345";

		// 验证11位手机号
		assertEquals(11, validPhone.length());
		assertNotEquals(11, invalidPhone.length());

		// 验证手机号格式（1开头）
		assertTrue(validPhone.startsWith("1"));
	}

	@Test
	@DisplayName("测试运动员年龄验证")
	void testAgeValidation() {
		// 正常年龄范围（6-70岁）
		testAthlete.setAge(25);
		assertTrue(testAthlete.getAge() >= 6 && testAthlete.getAge() <= 70);

		// 异常年龄（负数）
		Integer invalidAge = -5;
		assertFalse(invalidAge >= 6 && invalidAge <= 70);

		// 异常年龄（过大）
		Integer tooOld = 100;
		assertFalse(tooOld >= 6 && tooOld <= 70);
	}

	@Test
	@DisplayName("测试运动员信息完整性")
	void testAthleteInfoCompleteness() {
		// 必填字段验证
		assertNotNull(testAthlete.getPlayerName(), "姓名不能为空");
		assertNotNull(testAthlete.getGender(), "性别不能为空");
		assertNotNull(testAthlete.getAge(), "年龄不能为空");
		assertNotNull(testAthlete.getTeamName(), "队伍不能为空");
	}

	@Test
	@DisplayName("测试导出功能 - 数据转换正确性")
	void testExportDataConversion() {
		// 测试导出Excel时的数据转换
		AthleteExportExcel excel = new AthleteExportExcel();
		excel.setAthleteCode(testAthlete.getPlayerNo());
		excel.setPlayerName(testAthlete.getPlayerName());
		excel.setGender(testAthlete.getGender() == 1 ? "男" : "女");
		excel.setAge(testAthlete.getAge());
		excel.setTeamName(testAthlete.getTeamName());
		excel.setPhone(testAthlete.getContactPhone());
		excel.setProjects(testAthlete.getCategory());

		// 验证转换结果
		assertEquals("A001", excel.getAthleteCode());
		assertEquals("张三", excel.getPlayerName());
		assertEquals("男", excel.getGender());
		assertEquals(25, excel.getAge());
		assertEquals("北京队", excel.getTeamName());
		assertEquals("13800138000", excel.getPhone());
		assertEquals("长拳", excel.getProjects());
	}

	@Test
	@DisplayName("测试比赛状态转换为中文")
	void testCompetitionStatusToString() {
		// 测试各种状态的中文转换
		String status0 = testAthlete.getCompetitionStatus() == 0 ? "待出场" : "";
		assertEquals("待出场", status0);

		testAthlete.setCompetitionStatus(1);
		String status1 = testAthlete.getCompetitionStatus() == 1 ? "进行中" : "";
		assertEquals("进行中", status1);

		testAthlete.setCompetitionStatus(2);
		String status2 = testAthlete.getCompetitionStatus() == 2 ? "已完成" : "";
		assertEquals("已完成", status2);
	}

	@Test
	@DisplayName("测试运动员查询 - 按赛事ID")
	void testQueryByCompetitionId() {
		// 验证测试数据准备正确
		assertNotNull(mockAthletes);
		assertFalse(mockAthletes.isEmpty());
		assertEquals(1L, mockAthletes.get(0).getCompetitionId());

		// 验证运动员属于指定赛事
		Long expectedCompetitionId = 1L;
		boolean allMatch = mockAthletes.stream()
			.allMatch(athlete -> expectedCompetitionId.equals(athlete.getCompetitionId()));
		assertTrue(allMatch);
	}

	@Test
	@DisplayName("测试运动员信息更新")
	void testUpdateAthleteInfo() {
		// 记录原始值
		String originalPhone = testAthlete.getContactPhone();
		String originalTeam = testAthlete.getTeamName();

		// 修改运动员信息
		testAthlete.setContactPhone("13900139000");
		testAthlete.setTeamName("上海队");

		// 验证信息已更新
		assertEquals("13900139000", testAthlete.getContactPhone());
		assertEquals("上海队", testAthlete.getTeamName());
		assertNotEquals(originalPhone, testAthlete.getContactPhone());
		assertNotEquals(originalTeam, testAthlete.getTeamName());
	}
}
