package kr.itn.itnhub.process;

import kr.itn.itnhub.AbstractDbTest;
import kr.itn.itnhub.code.CodeService;
import kr.itn.itnhub.org.Organization;
import kr.itn.itnhub.org.OrganizationMapper;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;

import static org.assertj.core.api.Assertions.assertThat;

/**
 * "어느 값이 처리완료인가"가 코드표에서 온다는 것을 확인한다.
 *
 * <p>쿼리에 '처리완료'가 박혀 있던 시절에는 코드표를 바꿔도 집계가 그대로였다. 이 테스트는
 * 코드표의 done 속성을 옮기면 진행률도 따라 움직이는지를 본다 - 파라미터화가 형식만 바뀐 게
 * 아니라 실제로 동작하는지를 증명하는 자리다.</p>
 */
class ProcessDoneStatusTest extends AbstractDbTest {

    @Autowired
    ProcessService service;

    @Autowired
    OrganizationMapper orgMapper;

    @Autowired
    CodeService codeService;

    @Autowired
    JdbcTemplate jdbc;

    private Long orgId;

    @BeforeEach
    void setUp() {
        jdbc.update("delete from process_item");
        jdbc.update("delete from organization where org_no = '910'");

        Organization org = new Organization();
        org.setOrgNo("910");
        org.setOrgName("처리상태테스트기관");
        org.setChannelSlug("910");
        orgMapper.upsertBySeed(org);
        orgId = orgMapper.findByOrgNoAndOrgName("910", "처리상태테스트기관").getId();

        insert(1, "처리완료");
        insert(2, "처리완료");
        insert(3, "미처리");
    }

    @AfterEach
    void restore() {
        jdbc.update("update code set attrs = jsonb_set(attrs, '{done}', 'true') "
                + "where group_id = 'PROCESS_STATUS' and code = '처리완료'");
        jdbc.update("update code set attrs = jsonb_set(attrs, '{done}', 'false') "
                + "where group_id = 'PROCESS_STATUS' and code = '미처리'");
        codeService.reload();

        jdbc.update("delete from process_item");
        jdbc.update("delete from organization where org_no = '910'");
    }

    private void insert(int seq, String status) {
        jdbc.update("insert into process_item (org_id, seq, process_status) values (?, ?, ?)",
                orgId, seq, status);
    }

    @Test
    void 기본_설정에서는_처리완료가_완료로_집계된다() {
        ProcessPage page = service.list(orgId, null, null, null, null, null, 0, 30);

        assertThat(page.total()).isEqualTo(3);
        assertThat(page.done()).isEqualTo(2);
    }

    @Test
    void 코드표에서_done을_옮기면_집계도_따라_움직인다() {
        // '미처리'를 완료로, '처리완료'를 미완료로 뒤집는다. 쿼리에 값이 박혀 있었다면
        // 아무 변화도 없었을 것이다.
        jdbc.update("update code set attrs = jsonb_set(attrs, '{done}', 'false') "
                + "where group_id = 'PROCESS_STATUS' and code = '처리완료'");
        jdbc.update("update code set attrs = jsonb_set(attrs, '{done}', 'true') "
                + "where group_id = 'PROCESS_STATUS' and code = '미처리'");
        codeService.reload();

        ProcessPage page = service.list(orgId, null, null, null, null, null, 0, 30);

        assertThat(page.total()).isEqualTo(3);
        assertThat(page.done()).isEqualTo(1);
    }

    @Test
    void 상태_필터도_코드표를_따른다() {
        assertThat(service.list(orgId, null, null, null, null, "DONE", 0, 30).items()).hasSize(2);
        assertThat(service.list(orgId, null, null, null, null, "PENDING", 0, 30).items()).hasSize(1);

        jdbc.update("update code set attrs = jsonb_set(attrs, '{done}', 'false') "
                + "where group_id = 'PROCESS_STATUS' and code = '처리완료'");
        jdbc.update("update code set attrs = jsonb_set(attrs, '{done}', 'true') "
                + "where group_id = 'PROCESS_STATUS' and code = '미처리'");
        codeService.reload();

        assertThat(service.list(orgId, null, null, null, null, "DONE", 0, 30).items()).hasSize(1);
        assertThat(service.list(orgId, null, null, null, null, "PENDING", 0, 30).items()).hasSize(2);
    }
}
