package com.example.demo;

import com.example.demo.model.BusinessItem;
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 java.util.List;

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

/**
 * 业务管理服务的单元测试。
 * <p>覆盖业务新增、编辑、删除、提交、审核、驳回、归档、查询筛选等核心功能。</p>
 */
class BusinessServiceTest {

    private BusinessService businessService;

    @BeforeEach
    void setUp() {
        businessService = new BusinessService();
    }

    /**
     * 测试业务新增功能。
     *
     * @requirement(name="业务新增", id="SRS-F-02-001")
     */
    @Test
    @DisplayName("新增业务 - 应返回带有生成编号的业务")
    void testSave() {
        BusinessItem item = new BusinessItem();
        item.setBusinessType("采购申请");
        item.setContent("测试采购");
        item.setApplicantId(1L);

        BusinessItem saved = businessService.save(item);

        assertNotNull(saved);
        assertNotNull(saved.getBusinessId());
        assertNotNull(saved.getBusinessNo());
        assertEquals("草稿", saved.getStatus());
        assertEquals("采购申请", saved.getBusinessType());
    }

    /**
     * 测试业务编辑功能。
     *
     * @requirement(name="业务编辑", id="SRS-F-02-002")
     */
    @Test
    @DisplayName("编辑业务 - 草稿状态可编辑")
    void testUpdateDraft() {
        BusinessItem item = new BusinessItem();
        item.setBusinessType("请假申请");
        item.setContent("年假");
        item.setApplicantId(2L);
        BusinessItem saved = businessService.save(item);

        saved.setContent("修改为事假");
        BusinessItem updated = businessService.update(saved);

        assertNotNull(updated);
        assertEquals("修改为事假", updated.getContent());
    }

    /**
     * 测试业务编辑 - 非草稿状态不可编辑。
     *
     * @requirement(name="业务编辑", id="SRS-F-02-002")
     */
    @Test
    @DisplayName("编辑业务 - 非草稿状态不可编辑")
    void testUpdateNonDraft() {
        // 预置数据中 ID=2 是待审核状态
        BusinessItem item = new BusinessItem();
        item.setBusinessId(2L);
        item.setContent("尝试修改");
        BusinessItem updated = businessService.update(item);
        assertNull(updated);
    }

    /**
     * 测试业务删除 - 草稿可删除。
     *
     * @requirement(name="业务删除", id="SRS-F-02-003")
     */
    @Test
    @DisplayName("删除业务 - 草稿可删除")
    void testDeleteDraft() {
        // 预置数据中 ID=3 是草稿
        boolean deleted = businessService.deleteById(3L);
        assertTrue(deleted);
    }

    /**
     * 测试业务删除 - 非草稿不可删除。
     *
     * @requirement(name="业务删除", id="SRS-F-02-003")
     */
    @Test
    @DisplayName("删除业务 - 非草稿不可删除")
    void testDeleteNonDraft() {
        // 预置数据中 ID=2 是待审核
        boolean deleted = businessService.deleteById(2L);
        assertFalse(deleted);
    }

    /**
     * 测试业务提交。
     *
     * @requirement(name="业务提交", id="SRS-F-02-004")
     */
    @Test
    @DisplayName("提交业务 - 草稿转为待审核")
    void testSubmit() {
        BusinessItem submitted = businessService.submit(3L);
        assertNotNull(submitted);
        assertEquals("待审核", submitted.getStatus());
    }

    /**
     * 测试业务审核通过。
     *
     * @requirement(name="业务审核", id="SRS-F-02-005")
     */
    @Test
    @DisplayName("审核通过 - 待审核转为通过")
    void testApprove() {
        BusinessItem approved = businessService.approve(2L, 1L, "同意");
        assertNotNull(approved);
        assertEquals("通过", approved.getStatus());
        assertEquals(1L, approved.getAuditorId());
    }

    /**
     * 测试业务驳回。
     *
     * @requirement(name="业务驳回", id="SRS-F-02-006")
     */
    @Test
    @DisplayName("驳回业务 - 待审核转为驳回")
    void testReject() {
        // 先提交一个草稿
        businessService.submit(3L);
        BusinessItem rejected = businessService.reject(3L, 1L, "资料不全");
        assertNotNull(rejected);
        assertEquals("驳回", rejected.getStatus());
        assertEquals("资料不全", rejected.getComment());
    }

    /**
     * 测试业务归档。
     *
     * @requirement(name="业务归档", id="SRS-F-02-007")
     */
    @Test
    @DisplayName("归档业务 - 通过转为已归档")
    void testArchive() {
        // 先审核通过
        businessService.approve(2L, 1L, "同意");
        BusinessItem archived = businessService.archive(2L);
        assertNotNull(archived);
        assertEquals("已归档", archived.getStatus());
    }

    /**
     * 测试业务查询筛选。
     *
     * @requirement(name="业务查询筛选", id="SRS-F-02-008")
     */
    @Test
    @DisplayName("查询筛选 - 按类型和状态筛选")
    void testListWithFilters() {
        List<BusinessItem> result = businessService.list("采购申请", null, null);
        assertNotNull(result);
        assertTrue(result.stream().allMatch(b -> "采购申请".equals(b.getBusinessType())));

        List<BusinessItem> draftList = businessService.list(null, "草稿", null);
        assertTrue(draftList.stream().allMatch(b -> "草稿".equals(b.getStatus())));
    }

    /**
     * 测试业务查询 - 关键字搜索。
     *
     * @requirement(name="业务查询筛选", id="SRS-F-02-008")
     */
    @Test
    @DisplayName("查询筛选 - 按关键字搜索")
    void testListWithKeyword() {
        List<BusinessItem> result = businessService.list(null, null, "服务器");
        assertFalse(result.isEmpty());
        assertTrue(result.get(0).getContent().contains("服务器"));
    }

    /**
     * 测试完整的业务生命周期。
     *
     * @requirement(name="业务新增", id="SRS-F-02-001")
     * @requirement(name="业务提交", id="SRS-F-02-004")
     * @requirement(name="业务审核", id="SRS-F-02-005")
     * @requirement(name="业务归档", id="SRS-F-02-007")
     */
    @Test
    @DisplayName("完整生命周期：新增→提交→审核→归档")
    void testFullLifecycle() {
        // 新增
        BusinessItem item = new BusinessItem();
        item.setBusinessType("测试业务");
        item.setContent("生命周期测试");
        item.setApplicantId(1L);
        BusinessItem saved = businessService.save(item);
        assertEquals("草稿", saved.getStatus());

        // 提交
        BusinessItem submitted = businessService.submit(saved.getBusinessId());
        assertNotNull(submitted);
        assertEquals("待审核", submitted.getStatus());

        // 审核通过
        BusinessItem approved = businessService.approve(submitted.getBusinessId(), 2L, "同意");
        assertNotNull(approved);
        assertEquals("通过", approved.getStatus());

        // 归档
        BusinessItem archived = businessService.archive(approved.getBusinessId());
        assertNotNull(archived);
        assertEquals("已归档", archived.getStatus());
    }
}
