package com.sino.mci.inbound.service;

import com.sino.mci.channel.entity.Conversation;
import com.sino.mci.channel.entity.ConversationTagBinding;
import com.sino.mci.channel.repository.ConversationMapper;
import com.sino.mci.channel.repository.ConversationTagBindingMapper;
import com.sino.mci.crm.entity.Person;
import com.sino.mci.crm.entity.PersonTagBinding;
import com.sino.mci.crm.entity.Tag;
import com.sino.mci.crm.repository.PersonMapper;
import com.sino.mci.crm.repository.PersonTagBindingMapper;
import com.sino.mci.crm.repository.TagMapper;
import com.sino.mci.inbound.entity.MessageEvent;
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 java.util.List;
import java.util.Map;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.when;

@ExtendWith(MockitoExtension.class)
class InboundContextServiceTest {

    @Mock
    private ConversationMapper conversationMapper;
    @Mock
    private PersonMapper personMapper;
    @Mock
    private ConversationTagBindingMapper conversationTagBindingMapper;
    @Mock
    private PersonTagBindingMapper personTagBindingMapper;
    @Mock
    private TagMapper tagMapper;

    @InjectMocks
    private InboundContextService inboundContextService;

    @Test
    void shouldResolveConversationContext() {
        MessageEvent event = new MessageEvent();
        event.setConversationId(1L);
        event.setChannelType("wecom");
        event.setAccountId(100L);

        Conversation conversation = new Conversation();
        conversation.setId(1L);
        conversation.setContractId(10L);
        conversation.setSupplierId(20L);
        conversation.setInstitutionId(30L);
        conversation.setChannelCode("C001");
        conversation.setOwnerAccountId(200L);

        when(conversationMapper.selectById(1L)).thenReturn(conversation);

        ConversationTagBinding binding = new ConversationTagBinding();
        binding.setTagId(101L);
        when(conversationTagBindingMapper.selectList(any())).thenReturn(List.of(binding));

        Tag tag = new Tag();
        tag.setId(101L);
        tag.setTagPath("销售/华北组");
        when(tagMapper.selectById(101L)).thenReturn(tag);

        Map<String, Object> context = inboundContextService.resolveContext(event);

        assertThat(context)
                .containsEntry("contract_id", 10L)
                .containsEntry("supplier_id", 20L)
                .containsEntry("institution_id", 30L)
                .containsEntry("channel_code", "C001")
                .containsEntry("owner_account_id", 200L)
                .containsEntry("channel_type", "wecom")
                .containsEntry("account_id", 100L);
        assertThat(context).containsKey("conversation_tags");
        @SuppressWarnings("unchecked")
        List<String> tags = (List<String>) context.get("conversation_tags");
        assertThat(tags).containsExactly("销售/华北组");
    }

    @Test
    void shouldResolvePersonContext() {
        MessageEvent event = new MessageEvent();
        event.setPersonId(2L);
        event.setChannelType("wecom");
        event.setAccountId(100L);

        Person person = new Person();
        person.setId(2L);
        person.setPersonType(2);
        person.setInstitutionId(40L);
        person.setSupplierId(50L);

        when(personMapper.selectById(2L)).thenReturn(person);

        PersonTagBinding binding = new PersonTagBinding();
        binding.setTagId(102L);
        when(personTagBindingMapper.selectList(any())).thenReturn(List.of(binding));

        Tag tag = new Tag();
        tag.setId(102L);
        tag.setTagPath("供应商/技师");
        when(tagMapper.selectById(102L)).thenReturn(tag);

        Map<String, Object> context = inboundContextService.resolveContext(event);

        assertThat(context)
                .containsEntry("person_type", 2)
                .containsEntry("institution_id", 40L)
                .containsEntry("supplier_id", 50L)
                .containsEntry("channel_type", "wecom")
                .containsEntry("account_id", 100L);
        assertThat(context).containsKey("person_tags");
        @SuppressWarnings("unchecked")
        List<String> tags = (List<String>) context.get("person_tags");
        assertThat(tags).containsExactly("供应商/技师");
    }

    @Test
    void shouldMergeContextsWithoutOverwriting() {
        MessageEvent event = new MessageEvent();
        event.setConversationId(1L);
        event.setPersonId(2L);
        event.setChannelType("wecom");
        event.setAccountId(100L);

        Conversation conversation = new Conversation();
        conversation.setId(1L);
        conversation.setContractId(10L);
        conversation.setSupplierId(20L);
        conversation.setInstitutionId(30L);
        conversation.setChannelCode("C001");
        conversation.setOwnerAccountId(200L);

        Person person = new Person();
        person.setId(2L);
        person.setPersonType(3);
        person.setInstitutionId(40L);
        person.setSupplierId(60L);

        when(conversationMapper.selectById(1L)).thenReturn(conversation);
        when(personMapper.selectById(2L)).thenReturn(person);
        when(conversationTagBindingMapper.selectList(any())).thenReturn(List.of());
        when(personTagBindingMapper.selectList(any())).thenReturn(List.of());

        Map<String, Object> context = inboundContextService.resolveContext(event);

        assertThat(context)
                .containsEntry("contract_id", 10L)
                .containsEntry("channel_code", "C001")
                .containsEntry("owner_account_id", 200L)
                .containsEntry("person_type", 3)
                .containsEntry("institution_id", 30L)
                .containsEntry("supplier_id", 20L);
    }
}
