package com.ruoyi.ccdi.project.controller;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.ccdi.project.domain.dto.CcdiBankStatementQueryDTO;
import com.ruoyi.ccdi.project.domain.excel.CcdiBankStatementExcel;
import com.ruoyi.ccdi.project.domain.vo.CcdiBankStatementCounterpartyVO;
import com.ruoyi.ccdi.project.domain.vo.CcdiBankStatementDetailVO;
import com.ruoyi.ccdi.project.domain.vo.CcdiBankStatementFilterOptionsVO;
import com.ruoyi.ccdi.project.domain.vo.CcdiBankStatementListVO;
import com.ruoyi.ccdi.project.service.ICcdiBankStatementService;
import com.ruoyi.ccdi.project.service.CcdiProjectAccessService;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.page.TableDataInfo;
import org.junit.jupiter.api.AfterEach;
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.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.math.BigDecimal;
import java.util.List;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.same;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

@ExtendWith(MockitoExtension.class)
class CcdiBankStatementControllerTest {

    @InjectMocks
    private CcdiBankStatementController controller;

    @Mock
    private ICcdiBankStatementService bankStatementService;

    @Mock
    private CcdiProjectAccessService projectAccessService;

    @AfterEach
    void tearDown() {
        RequestContextHolder.resetRequestAttributes();
    }

    @Test
    void options_shouldReturnAjaxResultSuccess() {
        when(bankStatementService.getFilterOptions(100L)).thenReturn(new CcdiBankStatementFilterOptionsVO());

        AjaxResult result = controller.getOptions(100L);

        assertEquals(200, result.get("code"));
    }

    @Test
    void list_shouldReturnTableData() {
        MockHttpServletRequest request = new MockHttpServletRequest();
        request.setParameter("pageNum", "1");
        request.setParameter("pageSize", "10");
        RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(request));

        CcdiBankStatementQueryDTO queryDTO = new CcdiBankStatementQueryDTO();
        queryDTO.setProjectId(100L);
        CcdiBankStatementListVO row = new CcdiBankStatementListVO();
        row.setBankStatementId(1L);
        Page<CcdiBankStatementListVO> page = new Page<>(1, 10);
        page.setRecords(List.of(row));
        page.setTotal(1);
        when(bankStatementService.selectStatementPage(any(), same(queryDTO))).thenReturn(page);

        TableDataInfo result = controller.list(queryDTO);

        assertEquals(200, result.getCode());
        assertEquals(1L, result.getTotal());
        assertEquals(1, result.getRows().size());
    }

    @Test
    void counterpartyList_shouldReturnTableData() {
        MockHttpServletRequest request = new MockHttpServletRequest();
        request.setParameter("pageNum", "1");
        request.setParameter("pageSize", "10");
        RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(request));

        CcdiBankStatementQueryDTO queryDTO = new CcdiBankStatementQueryDTO();
        queryDTO.setProjectId(100L);
        CcdiBankStatementCounterpartyVO row = new CcdiBankStatementCounterpartyVO();
        row.setCustomerAccountName("测试对手方");
        row.setTotalCount(2L);
        Page<CcdiBankStatementCounterpartyVO> page = new Page<>(1, 10);
        page.setRecords(List.of(row));
        page.setTotal(1);
        when(bankStatementService.selectCounterpartyPage(any(), same(queryDTO))).thenReturn(page);

        TableDataInfo result = controller.counterpartyList(queryDTO);

        assertEquals(200, result.getCode());
        assertEquals(1L, result.getTotal());
        assertEquals(1, result.getRows().size());
        verify(projectAccessService).assertCanRead(100L);
    }

    @Test
    void detail_shouldReturnAjaxResultSuccess() {
        CcdiBankStatementDetailVO detailVO = new CcdiBankStatementDetailVO();
        detailVO.setBankStatementId(1000L);
        when(bankStatementService.getStatementDetail(
            1000L, "SUSPICIOUS_GAMBLING", "MODEL_RULE"
        )).thenReturn(detailVO);

        AjaxResult result = controller.getDetail(1000L, "SUSPICIOUS_GAMBLING", "MODEL_RULE");

        assertEquals(200, result.get("code"));
        assertEquals(detailVO, result.get("data"));
        verify(bankStatementService).getStatementDetail(
            1000L, "SUSPICIOUS_GAMBLING", "MODEL_RULE"
        );
    }

    @Test
    void export_shouldWriteExcelResponse() {
        MockHttpServletResponse response = new MockHttpServletResponse();
        CcdiBankStatementQueryDTO queryDTO = new CcdiBankStatementQueryDTO();
        CcdiBankStatementExcel row = new CcdiBankStatementExcel();
        row.setLeAccountNo("6222");
        row.setDisplayAmount(new BigDecimal("10.00"));
        when(bankStatementService.selectStatementListForExport(same(queryDTO))).thenReturn(List.of(row));

        controller.export(response, queryDTO);

        verify(bankStatementService).selectStatementListForExport(same(queryDTO));
        assertTrue(response.getContentType().startsWith("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"));
        assertTrue(response.getContentAsByteArray().length > 0);
    }
}
