package com.zcloud.personnel.positioning.command;

import com.zcloud.personnel.positioning.persistence.dataobject.OrgLocalCorpDO;
import com.zcloud.personnel.positioning.persistence.dataobject.OrgLocalDepartmentDO;
import com.zcloud.personnel.positioning.persistence.dataobject.OrgMatchSnapshotDO;
import com.zcloud.personnel.positioning.persistence.repository.OrgMatchRepository;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;

import java.util.Arrays;
import java.util.Collections;
import java.util.Map;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

class FindsCorpMappingServiceTest {
    private OrgMatchRepository repository;
    private FindsCorpMappingService service;

    @BeforeEach
    void setUp() {
        repository = mock(OrgMatchRepository.class);
        service = new FindsCorpMappingService(repository);
        when(repository.listCorpCandidates(any())).thenReturn(Collections.emptyList());
        when(repository.listDepartmentCandidates(anyString())).thenReturn(Collections.emptyList());
    }

    @Test
    void usesSavedMatchedMappingFirst() {
        OrgMatchSnapshotDO saved = new OrgMatchSnapshotDO();
        saved.setLocalCorpinfoId("LOCAL-1");
        saved.setLocalCorpinfoName("本平台公司");
        saved.setMatchType("CORP_NAME");
        when(repository.findMatched("FINDS", "第三方公司", "")).thenReturn(saved);

        FindsCorpMappingService.CorpMatch result = service.resolve("FINDS", "0", "第三方公司", null, null);

        assertEquals("LOCAL-1", result.getCorpinfoId());
        verify(repository, never()).listCorpCandidates(any());
        verify(repository).touch(anyString(), anyString(), anyString(), any());
    }

    @Test
    void exactCompanyNameIsPersistedAsMatched() {
        when(repository.listCorpCandidates(any())).thenAnswer(invocation -> {
            Map<String, Object> params = invocation.getArgument(0);
            return params.containsKey("corpinfoName")
                    ? Collections.singletonList(corp("LOCAL-2", "卸车队")) : Collections.emptyList();
        });

        FindsCorpMappingService.CorpMatch result = service.resolve("FINDS", "0", "卸车队", null, null);

        assertEquals("LOCAL-2", result.getCorpinfoId());
        assertSaved("MATCHED", "CORP_NAME");
    }

    @Test
    void departmentNameResolvesOwningCompany() {
        OrgLocalDepartmentDO department = new OrgLocalDepartmentDO();
        department.setDepartmentId(88L);
        department.setDepartmentName("卸车作业部");
        department.setRootCorpinfoId("LOCAL-DEP");
        department.setRootCorpinfoName("港区公司");
        when(repository.listDepartmentCandidates("卸车作业部"))
                .thenReturn(Collections.singletonList(department));

        FindsCorpMappingService.CorpMatch result = service.resolve(
                "FINDS", null, "第三方公司", "卸车作业部", null);

        assertEquals("LOCAL-DEP", result.getCorpinfoId());
        assertEquals(88L, result.getDepartmentId());
        assertSaved("MATCHED", "DEPARTMENT_NAME");
    }

    @Test
    void ambiguousSuffixDoesNotAssignCompany() {
        when(repository.listCorpCandidates(any())).thenAnswer(invocation -> {
            Map<String, Object> params = invocation.getArgument(0);
            return params.containsKey("corpinfoNameSuffix")
                    ? Arrays.asList(corp("LOCAL-3", "一公司卸车队"), corp("LOCAL-4", "二公司卸车队"))
                    : Collections.emptyList();
        });

        FindsCorpMappingService.CorpMatch result = service.resolve("FINDS", null, "卸车队", null, null);

        assertNull(result);
        assertSaved("AMBIGUOUS", "CORP_NAME_SUFFIX");
    }

    @Test
    void unknownOrganizationIsPersistedAsUnmatched() {
        FindsCorpMappingService.CorpMatch result = service.resolve("FINDS", null, "不存在的公司", null, null);

        assertNull(result);
        assertSaved("UNMATCHED", "CORP_NAME_SUFFIX");
    }

    private OrgLocalCorpDO corp(String id, String name) {
        OrgLocalCorpDO corp = new OrgLocalCorpDO();
        corp.setCorpinfoId(id);
        corp.setCorpinfoName(name);
        return corp;
    }

    private void assertSaved(String status, String matchType) {
        ArgumentCaptor<Map<String, Object>> captor = ArgumentCaptor.forClass(Map.class);
        verify(repository).upsert(captor.capture());
        assertEquals(status, captor.getValue().get("matchStatus"));
        assertEquals(matchType, captor.getValue().get("matchType"));
    }
}
