package com.ruoyi.ccdi.project.controller;

import com.ruoyi.ccdi.project.domain.dto.CcdiPullBankInfoSubmitDTO;
import com.ruoyi.ccdi.project.service.CcdiProjectAccessService;
import com.ruoyi.ccdi.project.service.ICcdiFileUploadService;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.core.domain.AjaxResult;
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.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.web.multipart.MultipartFile;

import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.List;
import java.util.Set;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

@ExtendWith(MockitoExtension.class)
class CcdiFileUploadControllerTest {

    private static final Long PROJECT_ID = 100L;

    @InjectMocks
    private CcdiFileUploadController controller;

    @Mock
    private ICcdiFileUploadService fileUploadService;

    @Mock
    private CcdiProjectAccessService projectAccessService;

    @AfterEach
    void tearDown() {
        SecurityContextHolder.clearContext();
    }

    @Test
    void parseIdCardFile_shouldReturnAjaxResultSuccess() {
        MockMultipartFile file = new MockMultipartFile(
            "file",
            "ids.xlsx",
            "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
            "test".getBytes(StandardCharsets.UTF_8)
        );
        when(fileUploadService.parseIdCardFile(file)).thenReturn(List.of("110101199001018888"));

        AjaxResult result = controller.parseIdCardFile(file);

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

    @Test
    void batchUpload_shouldDelegateFilenameValidationToService() {
        MultipartFile[] files = new MultipartFile[]{
            new MockMultipartFile(
                "files",
                "330101199001010011 - 流水.xl sx",
                "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
                "content".getBytes(StandardCharsets.UTF_8)
            )
        };

        setLoginUser(9527L, "admin");
        when(fileUploadService.batchUploadFiles(PROJECT_ID, files, "admin"))
            .thenReturn("batch-1");

        AjaxResult result = controller.batchUpload(PROJECT_ID, files);

        assertEquals(200, result.get("code"));
        assertEquals("batch-1", result.get("data"));
        verify(projectAccessService).assertCanOperate(PROJECT_ID);
        verify(fileUploadService).batchUploadFiles(PROJECT_ID, files, "admin");
    }

    @Test
    void pullBankInfo_shouldUseCurrentLoginUserInfo() {
        CcdiPullBankInfoSubmitDTO dto = new CcdiPullBankInfoSubmitDTO();
        dto.setProjectId(PROJECT_ID);
        dto.setIdCards(List.of("110101199001018888"));
        dto.setDataChannelCode("ZJRCU");
        dto.setStartDate("2026-03-01");
        dto.setEndDate("2026-03-10");

        setLoginUser(9527L, "admin");
        when(fileUploadService.submitPullBankInfo(PROJECT_ID, dto.getIdCards(), "ZJRCU", "2026-03-01", "2026-03-10", 9527L, "admin"))
            .thenReturn("batch-1");

        AjaxResult result = controller.pullBankInfo(dto);

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

    @Test
    void pullBankInfo_shouldAllowJzlWithoutDateRange() {
        CcdiPullBankInfoSubmitDTO dto = new CcdiPullBankInfoSubmitDTO();
        dto.setProjectId(PROJECT_ID);
        dto.setIdCards(List.of("110101199001018888"));
        dto.setDataChannelCode("JZL");

        setLoginUser(9527L, "admin");
        when(fileUploadService.submitPullBankInfo(PROJECT_ID, dto.getIdCards(), "JZL", null, null, 9527L, "admin"))
            .thenReturn("batch-1");

        AjaxResult result = controller.pullBankInfo(dto);

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

    @Test
    void pullBankInfo_shouldRejectUnsupportedDataChannelCode() {
        CcdiPullBankInfoSubmitDTO dto = new CcdiPullBankInfoSubmitDTO();
        dto.setProjectId(PROJECT_ID);
        dto.setIdCards(List.of("110101199001018888"));
        dto.setDataChannelCode("OTHER");

        AjaxResult result = controller.pullBankInfo(dto);

        assertEquals(500, result.get("code"));
        assertEquals("流水来源不支持", result.get("msg"));
    }

    @Test
    void deleteFile_shouldUseCurrentLoginUserId() {
        setLoginUser(9527L, "admin");
        when(fileUploadService.deleteFileUploadRecord(123L, 9527L))
            .thenReturn("删除成功");

        AjaxResult result = controller.deleteFile(123L);

        assertEquals(200, result.get("code"));
        assertEquals("删除成功", result.get("msg"));
        verify(fileUploadService).deleteFileUploadRecord(123L, 9527L);
    }

    private void setLoginUser(Long userId, String username) {
        SysUser user = new SysUser();
        user.setUserName(username);
        LoginUser loginUser = new LoginUser(user, Set.of("*:*:*"));
        loginUser.setUserId(userId);
        UsernamePasswordAuthenticationToken authentication =
            new UsernamePasswordAuthenticationToken(loginUser, null, Collections.emptyList());
        SecurityContextHolder.getContext().setAuthentication(authentication);
    }
}
