package com.example.demo;

import com.example.demo.model.*;
import com.example.demo.service.BusinessService;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.List;
import java.util.Map;

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

/**
 * 业务服务层单元测试。
 *
 * <p>对 {@link BusinessService} 的核心业务逻辑进行单元测试，覆盖用户管理、
 * 角色管理、部门管理、业务数据全生命周期、日志审计等功能。</p>
 */
@SpringBootTest
class BusinessServiceTest {

    @Autowired
    private BusinessService businessService;

    @BeforeEach
    void setUp() {
        // 每个测试方法前重置数据 - 内存数据已在 @PostConstruct 初始化
    }

    // ==================== 用户管理 ====================

    /**
     * 测试新增用户。
     *
     * @requirement(name="用户管理", id="SRS-IMS_F-001")
     */
    @Test
    @DisplayName("新增用户 - 应成功创建并返回带ID的用户")
    void testCreateUser() {
        User user = new User(null, "testuser", "123456", "测试用户", 1L, 1L, "13800138000", 1);
        User created = businessService.createUser(user);
        assertNotNull(created);
        assertNotNull(created.getUserId());
        assertEquals("testuser", created.getUsername());
    }

    /**
     * 测试查询用户 - 根据ID查询。
     *
     * @requirement(name="用户管理", id="SRS-IMS_F-001")
     */
    @Test
    @DisplayName("查询用户 - 根据ID应返回正确用户")
    void testGetUserById() {
        User user = businessService.getUserById(1L);
        assertNotNull(user);
        assertEquals("admin", user.getUsername());
    }

    /**
     * 测试分页查询用户。
     *
     * @requirement(name="用户管理", id="SRS-IMS_F-001")
     */
    @Test
    @DisplayName("分页查询用户 - 应返回分页结果")
    void testQueryUsers() {
        PageResult<User> result = businessService.queryUsers(null, 1, 10);
        assertNotNull(result);
        assertTrue(result.getTotal() > 0);
        assertFalse(result.getRecords().isEmpty());
    }

    /**
     * 测试编辑用户。
     *
     * @requirement(name="用户管理", id="SRS-IMS_F-001")
     */
    @Test
    @DisplayName("编辑用户 - 应更新用户信息")
    void testUpdateUser() {
        User update = new User();
        update.setRealName("更新后的姓名");
        User updated = businessService.updateUser(1L, update);
        assertNotNull(updated);
        assertEquals("更新后的姓名", updated.getRealName());
    }

    /**
     * 测试删除用户。
     *
     * @requirement(name="用户管理", id="SRS-IMS_F-001")
     */
    @Test
    @DisplayName("删除用户 - 应成功删除")
    void testDeleteUser() {
        boolean result = businessService.deleteUser(3L);
        assertTrue(result);
        assertNull(businessService.getUserById(3L));
    }

    // ==================== 角色管理 ====================

    /**
     * 测试新增角色。
     *
     * @requirement(name="角色管理", id="SRS-IMS_F-002")
     */
    @Test
    @DisplayName("新增角色 - 应成功创建")
    void testCreateRole() {
        Role role = new Role(null, "测试角色", "TEST_ROLE", "测试描述", 1, false, List.of());
        Role created = businessService.createRole(role);
        assertNotNull(created);
        assertNotNull(created.getRoleId());
        assertEquals("测试角色", created.getRoleName());
    }

    /**
     * 测试删除超级管理员角色（应被禁止）。
     *
     * @requirement(name="角色管理", id="SRS-IMS_F-002")
     */
    @Test
    @DisplayName("删除超级管理员角色 - 应返回false禁止删除")
    void testDeleteSuperAdminRole() {
        Boolean result = businessService.deleteRole(1L);
        assertNotNull(result);
        assertFalse(result);
    }

    /**
     * 测试角色权限分配。
     *
     * @requirement(name="角色权限分配", id="SRS-IMS_F-006")
     */
    @Test
    @DisplayName("角色权限分配 - 应成功分配权限")
    void testAssignPermissions() {
        List<String> permissions = List.of("business:view", "business:add", "business:edit");
        Role role = businessService.assignPermissions(2L, permissions);
        assertNotNull(role);
        assertEquals(permissions, role.getPermissionCodes());
    }

    // ==================== 部门管理 ====================

    /**
     * 测试新增部门。
     *
     * @requirement(name="部门管理", id="SRS-IMS_F-003")
     */
    @Test
    @DisplayName("新增部门 - 应成功创建")
    void testCreateDept() {
        Dept dept = new Dept(null, "测试部门", 1L, 1, 1, null);
        Dept created = businessService.createDept(dept);
        assertNotNull(created);
        assertNotNull(created.getDeptId());
        assertEquals("测试部门", created.getDeptName());
    }

    /**
     * 测试获取部门树形结构。
     *
     * @requirement(name="部门管理", id="SRS-IMS_F-003")
     */
    @Test
    @DisplayName("获取部门树 - 应返回树形结构")
    void testGetDeptTree() {
        List<Dept> tree = businessService.getDeptTree();
        assertNotNull(tree);
        assertFalse(tree.isEmpty());
    }

    // ==================== 业务数据管理 ====================

    /**
     * 测试新增业务数据。
     *
     * @requirement(name="业务新增", id="SRS-IMS_F-010")
     */
    @Test
    @DisplayName("新增业务数据 - 应创建并默认草稿状态")
    void testCreateBusinessItem() {
        BusinessItem item = new BusinessItem(null, "测试业务", "测试内容", "采购", "testuser", null, null, null, null);
        BusinessItem created = businessService.createBusinessItem(item);
        assertNotNull(created);
        assertNotNull(created.getId());
        assertEquals("DRAFT", created.getStatus());
    }

    /**
     * 测试提交业务审核。
     *
     * @requirement(name="业务提交", id="SRS-IMS_F-013")
     */
    @Test
    @DisplayName("提交业务审核 - 状态应从草稿变为已提交")
    void testSubmitBusinessItem() {
        // 先创建草稿
        BusinessItem item = new BusinessItem(null, "提交测试", "内容", "报销", "testuser", null, null, null, null);
        BusinessItem created = businessService.createBusinessItem(item);
        // 提交
        BusinessItem submitted = businessService.submitBusinessItem(created.getId());
        assertNotNull(submitted);
        assertEquals("SUBMITTED", submitted.getStatus());
    }

    /**
     * 测试审核通过业务。
     *
     * @requirement(name="业务审核", id="SRS-IMS_F-014")
     */
    @Test
    @DisplayName("审核通过 - 状态应从已提交变为已通过")
    void testApproveBusinessItem() {
        // 先创建并提交
        BusinessItem item = new BusinessItem(null, "审核测试", "内容", "合同", "testuser", null, null, null, null);
        BusinessItem created = businessService.createBusinessItem(item);
        businessService.submitBusinessItem(created.getId());
        // 审核通过
        BusinessItem approved = businessService.approveBusinessItem(created.getId(), "审核通过，同意执行");
        assertNotNull(approved);
        assertEquals("APPROVED", approved.getStatus());
    }

    /**
     * 测试驳回业务。
     *
     * @requirement(name="业务驳回", id="SRS-IMS_F-015")
     */
    @Test
    @DisplayName("驳回业务 - 状态应从已提交变为已驳回")
    void testRejectBusinessItem() {
        BusinessItem item = new BusinessItem(null, "驳回测试", "内容", "采购", "testuser", null, null, null, null);
        BusinessItem created = businessService.createBusinessItem(item);
        businessService.submitBusinessItem(created.getId());
        BusinessItem rejected = businessService.rejectBusinessItem(created.getId(), "资料不全，请补充");
        assertNotNull(rejected);
        assertEquals("REJECTED", rejected.getStatus());
        assertEquals("资料不全，请补充", rejected.getReviewComment());
    }

    /**
     * 测试归档业务。
     *
     * @requirement(name="业务归档", id="SRS-IMS_F-016")
     */
    @Test
    @DisplayName("归档业务 - 状态应从已通过变为已归档")
    void testArchiveBusinessItem() {
        BusinessItem item = new BusinessItem(null, "归档测试", "内容", "项目", "testuser", null, null, null, null);
        BusinessItem created = businessService.createBusinessItem(item);
        businessService.submitBusinessItem(created.getId());
        businessService.approveBusinessItem(created.getId(), "同意");
        BusinessItem archived = businessService.archiveBusinessItem(created.getId());
        assertNotNull(archived);
        assertEquals("ARCHIVED", archived.getStatus());
    }

    /**
     * 测试删除业务数据。
     *
     * @requirement(name="业务删除", id="SRS-IMS_F-012")
     */
    @Test
    @DisplayName("删除业务数据 - 应成功删除")
    void testDeleteBusinessItem() {
        BusinessItem item = new BusinessItem(null, "删除测试", "待删除", "其他", "testuser", null, null, null, null);
        BusinessItem created = businessService.createBusinessItem(item);
        boolean result = businessService.deleteBusinessItem(created.getId());
        assertTrue(result);
        assertNull(businessService.getBusinessItemById(created.getId()));
    }

    /**
     * 测试查询筛选。
     *
     * @requirement(name="查询筛选", id="SRS-IMS_F-017")
     */
    @Test
    @DisplayName("查询筛选 - 应支持多条件组合筛选")
    void testQueryBusinessItems() {
        PageResult<BusinessItem> result = businessService.queryBusinessItems(null, "采购", null, 1, 10);
        assertNotNull(result);
        assertTrue(result.getTotal() >= 1);
        result.getRecords().forEach(item -> assertEquals("采购", item.getType()));
    }

    // ==================== 数据统计分析 ====================

    /**
     * 测试数据汇总。
     *
     * @requirement(name="数据汇总", id="SRS-IMS_F-018")
     */
    @Test
    @DisplayName("数据汇总 - 应按类型返回统计结果")
    void testGetBusinessSummary() {
        Map<String, Long> summary = businessService.getBusinessSummary();
        assertNotNull(summary);
        assertFalse(summary.isEmpty());
    }

    /**
     * 测试图表数据。
     *
     * @requirement(name="图表展示", id="SRS-IMS_F-019")
     */
    @Test
    @DisplayName("图表数据 - 应按状态返回统计结果")
    void testGetChartData() {
        Map<String, Long> chart = businessService.getChartData();
        assertNotNull(chart);
        assertFalse(chart.isEmpty());
    }

    /**
     * 测试自定义查询。
     *
     * @requirement(name="自定义查询", id="SRS-IMS_F-020")
     */
    @Test
    @DisplayName("自定义查询 - 应支持自定义条件过滤")
    void testCustomQuery() {
        Map<String, String> conditions = Map.of("type", "采购");
        List<BusinessItem> result = businessService.customQuery(conditions);
        assertNotNull(result);
        result.forEach(item -> assertEquals("采购", item.getType()));
    }

    /**
     * 测试报表导出。
     *
     * @requirement(name="报表导出", id="SRS-IMS_F-021")
     */
    @Test
    @DisplayName("报表导出 - 应返回所有业务数据")
    void testExportReport() {
        List<BusinessItem> report = businessService.exportReport();
        assertNotNull(report);
        assertFalse(report.isEmpty());
    }

    /**
     * 测试数据台账生成。
     *
     * @requirement(name="数据台账生成", id="SRS-IMS_F-022")
     */
    @Test
    @DisplayName("数据台账生成 - 应按类型分组返回台账")
    void testGenerateLedger() {
        Map<String, List<BusinessItem>> ledger = businessService.generateLedger();
        assertNotNull(ledger);
        assertFalse(ledger.isEmpty());
    }

    // ==================== 日志审计管理 ====================

    /**
     * 测试登录日志记录。
     *
     * @requirement(name="登录日志记录", id="SRS-IMS_F-023")
     */
    @Test
    @DisplayName("登录日志记录 - 应成功记录登录日志")
    void testRecordLoginLog() {
        businessService.recordLoginLog("testuser", "192.168.1.1", "SUCCESS");
        PageResult<LogRecord> logs = businessService.queryLogs("LOGIN", "testuser", null, 1, 10);
        assertTrue(logs.getTotal() >= 1);
    }

    /**
     * 测试操作日志记录。
     *
     * @requirement(name="操作日志记录", id="SRS-IMS_F-024")
     */
    @Test
    @DisplayName("操作日志记录 - 应成功记录操作日志")
    void testRecordOperationLog() {
        businessService.recordOperationLog("testuser", "测试操作");
        PageResult<LogRecord> logs = businessService.queryLogs("OPERATION", "testuser", null, 1, 10);
        assertTrue(logs.getTotal() >= 1);
    }

    /**
     * 测试异常日志记录。
     *
     * @requirement(name="异常日志记录", id="SRS-IMS_F-025")
     */
    @Test
    @DisplayName("异常日志记录 - 应成功记录异常日志")
    void testRecordExceptionLog() {
        businessService.recordExceptionLog("testuser", "java.lang.NullPointerException: test");
        PageResult<LogRecord> logs = businessService.queryLogs("EXCEPTION", "testuser", null, 1, 10);
        assertTrue(logs.getTotal() >= 1);
    }

    /**
     * 测试日志溯源查询。
     *
     * @requirement(name="日志溯源查询", id="SRS-IMS_F-026")
     */
    @Test
    @DisplayName("日志溯源查询 - 应支持多条件组合查询")
    void testQueryLogs() {
        PageResult<LogRecord> logs = businessService.queryLogs(null, null, null, 1, 10);
        assertNotNull(logs);
        assertTrue(logs.getTotal() > 0);
    }

    // ==================== 菜单/按钮/数据权限 ====================

    /**
     * 测试获取角色菜单（动态菜单加载）。
     *
     * @requirement(name="菜单权限管理", id="SRS-IMS_F-007")
     */
    @Test
    @DisplayName("获取角色菜单 - 超级管理员应返回完整菜单")
    void testGetMenusBySuperAdmin() {
        List<TreeNode> menus = businessService.getMenusByRole(1L);
        assertNotNull(menus);
        assertFalse(menus.isEmpty());
    }

    /**
     * 测试获取按钮权限。
     *
     * @requirement(name="按钮权限管理", id="SRS-IMS_F-008")
     */
    @Test
    @DisplayName("获取按钮权限 - 超级管理员应返回所有按钮标识")
    void testGetButtonPermissions() {
        List<String> permissions = businessService.getButtonPermissions(1L);
        assertNotNull(permissions);
        assertFalse(permissions.isEmpty());
    }

    /**
     * 测试数据权限范围。
     *
     * @requirement(name="数据权限分级管控", id="SRS-IMS_F-009")
     */
    @Test
    @DisplayName("获取数据权限 - 超级管理员应返回所有部门")
    void testGetDataScope() {
        List<Long> scope = businessService.getDataScope(1L);
        assertNotNull(scope);
        assertTrue(scope.size() >= 1);
    }

    // ==================== 字典管理 ====================

    /**
     * 测试查询字典。
     *
     * @requirement(name="字典管理", id="SRS-IMS_F-004")
     */
    @Test
    @DisplayName("查询字典 - 应按类型过滤返回字典项")
    void testQueryDict() {
        List<DictItem> items = businessService.queryDictItems("business_type", null);
        assertNotNull(items);
        assertFalse(items.isEmpty());
        items.forEach(item -> assertEquals("business_type", item.getDictType()));
    }

    /**
     * 测试新增字典项。
     *
     * @requirement(name="字典管理", id="SRS-IMS_F-004")
     */
    @Test
    @DisplayName("新增字典项 - 应成功创建")
    void testCreateDictItem() {
        DictItem item = new DictItem(null, "test_type", "测试类型", "TEST_KEY", "测试值", 1, 1);
        DictItem created = businessService.createDictItem(item);
        assertNotNull(created);
        assertNotNull(created.getDictId());
    }

    // ==================== 参数配置 ====================

    /**
     * 测试查询参数配置。
     *
     * @requirement(name="参数配置", id="SRS-IMS_F-005")
     */
    @Test
    @DisplayName("查询参数配置 - 应返回所有配置项")
    void testGetAllConfigs() {
        List<SystemConfig> configs = businessService.getAllConfigs();
        assertNotNull(configs);
        assertFalse(configs.isEmpty());
    }

    /**
     * 测试新增参数配置。
     *
     * @requirement(name="参数配置", id="SRS-IMS_F-005")
     */
    @Test
    @DisplayName("新增参数配置 - 应成功创建")
    void testCreateConfig() {
        SystemConfig config = new SystemConfig(null, "test.key", "test_value", "测试配置", 1);
        SystemConfig created = businessService.createConfig(config);
        assertNotNull(created);
        assertNotNull(created.getConfigId());
    }

    // ==================== 标准化接口与第三方对接 ====================

    /**
     * 测试获取标准API定义。
     *
     * @requirement(name="标准化接口预留", id="SRS-IMS_F-027")
     */
    @Test
    @DisplayName("标准化接口定义 - 应返回接口列表")
    void testGetStandardApiDefinitions() {
        List<Map<String, String>> apis = businessService.getStandardApiDefinitions();
        assertNotNull(apis);
        assertFalse(apis.isEmpty());
    }

    /**
     * 测试第三方数据导入。
     *
     * @requirement(name="第三方数据对接", id="SRS-IMS_F-028")
     */
    @Test
    @DisplayName("第三方数据导入 - 应返回导入结果")
    void testImportExternalData() {
        List<Map<String, String>> data = List.of(
                Map.of("title", "外部导入1", "content", "内容1", "type", "外部"),
                Map.of("title", "外部导入2", "content", "内容2", "type", "外部")
        );
        Map<String, Object> result = businessService.importExternalData(data);
        assertNotNull(result);
        assertEquals(2, result.get("successCount"));
    }

    /**
     * 测试数据同步。
     *
     * @requirement(name="数据同步", id="SRS-IMS_F-029")
     */
    @Test
    @DisplayName("数据同步 - 应返回同步结果")
    void testExecuteDataSync() {
        Map<String, Object> result = businessService.executeDataSync("PUSH");
        assertNotNull(result);
        assertEquals("SUCCESS", result.get("status"));
    }
}
