package com.starry.admin.modules.weichat.service;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import com.starry.admin.modules.clerk.module.entity.PlayClerkUserInfoEntity;
import com.starry.admin.modules.clerk.module.enums.ListingStatus;
import com.starry.admin.modules.clerk.module.enums.OnboardingStatus;
import com.starry.admin.modules.order.module.constant.OrderConstant;
import com.starry.admin.modules.system.module.entity.SysTenantEntity;
import com.starry.admin.modules.system.service.impl.SysTenantServiceImpl;
import java.util.Arrays;
import java.util.List;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.api.WxMpTemplateMsgService;
import me.chanjar.weixin.mp.bean.template.WxMpTemplateData;
import me.chanjar.weixin.mp.bean.template.WxMpTemplateMessage;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.ArgumentCaptor;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

@ExtendWith(MockitoExtension.class)
class WxCustomMpServiceTest {

    private static final String TENANT_ID = "tenant-1";
    private static final String APP_ID = "wx-app";

    @Mock
    private WxMpService wxMpService;

    @Mock
    private WxMpTemplateMsgService templateMsgService;

    @Mock
    private SysTenantServiceImpl tenantService;

    @Mock
    private com.starry.admin.modules.custom.service.IPlayCustomUserInfoService customUserInfoService;

    @Mock
    private com.starry.admin.modules.personnel.service.IPlayPersonnelAdminInfoService playPersonnelAdminInfoService;

    @Mock
    private com.starry.admin.modules.clerk.service.IPlayClerkUserInfoService clerkUserInfoService;

    @Mock
    private ThreadPoolTaskExecutor executor;

    @InjectMocks
    private WxCustomMpService wxCustomMpService;

    private SysTenantEntity buildTenant() {
        return new SysTenantEntity()
                .setTenantId(TENANT_ID)
                .setTenantKey("tenant-key")
                .setAppId(APP_ID)
                .setSecret("wx-secret")
                .setXindingdanshoulitongzhiTemplateId("template-create-order");
    }

    @Test
    void sendCreateOrderMessageUsesOrderLabelResolver() throws WxErrorException {
        SysTenantEntity tenant = buildTenant();

        when(tenantService.selectSysTenantByTenantId(TENANT_ID)).thenReturn(tenant);
        when(wxMpService.switchoverTo(tenant.getAppId())).thenReturn(wxMpService);
        when(wxMpService.getTemplateMsgService()).thenReturn(templateMsgService);

        PlayClerkUserInfoEntity clerkDetails = new PlayClerkUserInfoEntity();
        clerkDetails.setId("clerk-1");
        clerkDetails.setNickname("Lily");
        when(clerkUserInfoService.selectByOpenid("openid-clerk")).thenReturn(clerkDetails);

        wxCustomMpService.sendCreateOrderMessage(
                TENANT_ID,
                "openid-clerk",
                "ORDER-001",
                "88.88",
                "伴聊套餐",
                "order-1",
                OrderConstant.PlaceType.REWARD.getCode(),
                OrderConstant.RewardType.GIFT.getCode());

        ArgumentCaptor<WxMpTemplateMessage> captor = ArgumentCaptor.forClass(WxMpTemplateMessage.class);
        verify(templateMsgService).sendTemplateMsg(captor.capture());

        WxMpTemplateMessage message = captor.getValue();
        assertThat(message.getTemplateId()).isEqualTo(tenant.getXindingdanshoulitongzhiTemplateId());
        assertThat(message.getToUser()).isEqualTo("openid-clerk");
        assertThat(message.getUrl())
                .isEqualTo("https://" + tenant.getTenantKey() + ".julyharbor.com/clerk/#/orderDetail/order-1");

        List<WxMpTemplateData> data = message.getData();
        assertThat(data)
                .filteredOn(templateData -> "short_thing5".equals(templateData.getName()))
                .singleElement()
                .extracting(WxMpTemplateData::getValue)
                .isEqualTo("礼物");
        assertThat(data)
                .filteredOn(templateData -> "character_string9".equals(templateData.getName()))
                .singleElement()
                .extracting(WxMpTemplateData::getValue)
                .isEqualTo("ORDER-001");
    }

    @Test
    void sendCreateOrderMessageBatchFiltersInactiveClerksAndForwardsLabel() throws WxErrorException {
        SysTenantEntity tenant = buildTenant();

        when(tenantService.selectSysTenantByTenantId(TENANT_ID)).thenReturn(tenant);
        when(wxMpService.switchoverTo(anyString())).thenReturn(wxMpService);
        when(wxMpService.getTemplateMsgService()).thenReturn(templateMsgService);

        doAnswer(invocation -> {
            Runnable runnable = invocation.getArgument(0);
            runnable.run();
            return null;
        }).when(executor).execute(any(Runnable.class));

        PlayClerkUserInfoEntity eligible = new PlayClerkUserInfoEntity();
        eligible.setTenantId(TENANT_ID);
        eligible.setOpenid("openid-eligible");
        eligible.setOnboardingState(OnboardingStatus.ACTIVE.getCode());
        eligible.setListingState(ListingStatus.LISTED.getCode());

        PlayClerkUserInfoEntity offboarded = new PlayClerkUserInfoEntity();
        offboarded.setTenantId(TENANT_ID);
        offboarded.setOpenid("openid-offboarded");
        offboarded.setOnboardingState(OnboardingStatus.OFFBOARDED.getCode());
        offboarded.setListingState(ListingStatus.LISTED.getCode());

        PlayClerkUserInfoEntity delisted = new PlayClerkUserInfoEntity();
        delisted.setTenantId(TENANT_ID);
        delisted.setOpenid("openid-delisted");
        delisted.setOnboardingState(OnboardingStatus.ACTIVE.getCode());
        delisted.setListingState(ListingStatus.DELISTED.getCode());

        PlayClerkUserInfoEntity clerkDetails = new PlayClerkUserInfoEntity();
        clerkDetails.setId("clerk-eligible");
        clerkDetails.setNickname("Kara");
        when(clerkUserInfoService.selectByOpenid("openid-eligible")).thenReturn(clerkDetails);

        wxCustomMpService.sendCreateOrderMessageBatch(
                Arrays.asList(eligible, offboarded, delisted, null),
                "ORDER-002",
                "45.00",
                "单人畅聊",
                "order-2",
                OrderConstant.PlaceType.SPECIFIED.getCode(),
                OrderConstant.RewardType.NOT_APPLICABLE.getCode());

        ArgumentCaptor<WxMpTemplateMessage> captor = ArgumentCaptor.forClass(WxMpTemplateMessage.class);
        verify(templateMsgService, times(1)).sendTemplateMsg(captor.capture());

        WxMpTemplateMessage message = captor.getValue();
        assertThat(message.getToUser()).isEqualTo("openid-eligible");
        assertThat(message.getData())
                .filteredOn(templateData -> "short_thing5".equals(templateData.getName()))
                .singleElement()
                .extracting(WxMpTemplateData::getValue)
                .isEqualTo("指定单");
    }
}
