package com.ruoyi.web.modules.circulation.service.impl;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import java.io.File;
import java.nio.file.Files;

import com.ruoyi.common.config.RuoYiConfig;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.web.modules.circulation.domain.BizTradeMarket;
import com.ruoyi.web.modules.circulation.mapper.BizTradeMarketMapper;
import com.ruoyi.web.modules.circulation.support.TradeMarketReferenceChecker;
import com.ruoyi.web.modules.circulation.support.TradeMarketRules;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.api.io.TempDir;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

@ExtendWith(MockitoExtension.class)
@DisplayName("BizTradeMarketServiceImpl")
class BizTradeMarketServiceImplTest
{
    private static final String VALID_PHONE = "13800138000";

    @TempDir
    File tempDir;

    @Mock
    private BizTradeMarketMapper mapper;

    @Mock
    private TradeMarketReferenceChecker referenceChecker;

    @InjectMocks
    private BizTradeMarketServiceImpl service;

    @BeforeEach
    void setUp()
    {
        new RuoYiConfig().setProfile(tempDir.getAbsolutePath());
    }

    @AfterEach
    void tearDown()
    {
        new RuoYiConfig().setProfile(null);
    }

    @Test
    @DisplayName("名称重复")
    void duplicateName()
    {
        when(mapper.countBizTradeMarketByNameExcludeId(eq("巴青市场"), isNull())).thenReturn(1);
        BizTradeMarket row = sampleRow();
        row.setMarketName("巴青市场");
        ServiceException ex = assertThrows(ServiceException.class, () -> service.insertBizTradeMarket(row));
        assertTrue(ex.getMessage().contains("市场名称已存在"));
        verify(mapper, never()).insertBizTradeMarket(any());
    }

    @Test
    @DisplayName("新增落库")
    void insert()
    {
        when(mapper.countBizTradeMarketByNameExcludeId(any(), isNull())).thenReturn(0);
        when(mapper.insertBizTradeMarket(any())).thenReturn(1);
        BizTradeMarket row = sampleRow();
        row.setOperateStatus(null);
        assertEquals(1, service.insertBizTradeMarket(row));
        verify(mapper).insertBizTradeMarket(argThat(r ->
                TradeMarketRules.DEL_FLAG_NORMAL.equals(r.getDelFlag())
                        && r.getOperateStatus() == TradeMarketRules.OPERATE_STATUS_NORMAL));
    }

    @Test
    @DisplayName("逻辑删除")
    void logicDelete()
    {
        BizTradeMarket db = sampleRow();
        db.setId(5L);
        when(mapper.selectBizTradeMarketByIdAny(5L)).thenReturn(db);
        when(referenceChecker.hasReference(5L)).thenReturn(false);
        when(mapper.logicDeleteBizTradeMarketByIds(any(), eq("tester"))).thenReturn(1);
        assertEquals(1, service.deleteBizTradeMarketByIds(new Long[] { 5L }, "tester"));
    }

    @Test
    @DisplayName("删除有关联")
    void deleteBlockedByReference()
    {
        BizTradeMarket db = sampleRow();
        db.setId(8L);
        when(mapper.selectBizTradeMarketByIdAny(8L)).thenReturn(db);
        when(referenceChecker.hasReference(8L)).thenReturn(true);
        ServiceException ex = assertThrows(ServiceException.class,
                () -> service.deleteBizTradeMarketByIds(new Long[] { 8L }, "tester"));
        assertTrue(ex.getMessage().contains("关联业务"));
        verify(mapper, never()).logicDeleteBizTradeMarketByIds(any(), any());
    }

    @Test
    @DisplayName("删除清照片")
    void deleteClearsPhoto() throws Exception
    {
        String rel = "upload/2025/market-old.jpg";
        File disk = new File(tempDir, rel.replace('/', File.separatorChar));
        Files.createDirectories(disk.getParentFile().toPath());
        Files.write(disk.toPath(), new byte[] { 1 });
        String resourcePath = Constants.RESOURCE_PREFIX + "/" + rel;

        BizTradeMarket db = sampleRow();
        db.setId(6L);
        db.setPhotoFilePath(resourcePath);
        when(mapper.selectBizTradeMarketByIdAny(6L)).thenReturn(db);
        when(referenceChecker.hasReference(6L)).thenReturn(false);
        when(mapper.logicDeleteBizTradeMarketByIds(any(), eq("u"))).thenReturn(1);

        assertEquals(1, service.deleteBizTradeMarketByIds(new Long[] { 6L }, "u"));
        assertTrue(!disk.exists());
    }

    @Test
    @DisplayName("详情填充运营状态名")
    void detailEnrichStatusName()
    {
        BizTradeMarket db = sampleRow();
        db.setId(1L);
        db.setOperateStatus(TradeMarketRules.OPERATE_STATUS_SUSPENDED);
        when(mapper.selectBizTradeMarketById(1L)).thenReturn(db);
        BizTradeMarket got = service.selectBizTradeMarketById(1L);
        assertEquals("停业", got.getOperateStatusName());
    }

    private static BizTradeMarket sampleRow()
    {
        BizTradeMarket r = new BizTradeMarket();
        r.setMarketName("巴青交易市场");
        r.setDetailAddress("西藏那曲市巴青县交易路1号");
        r.setPersonInCharge("王五");
        r.setContactPhone(VALID_PHONE);
        r.setOperateStatus(TradeMarketRules.OPERATE_STATUS_NORMAL);
        return r;
    }
}
