package com.zcloud.personnel.positioning.command.query;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.zcloud.personnel.positioning.command.FindsCorpMappingService;
import com.zcloud.personnel.positioning.integration.finds.FindsOpenApiClient;
import com.zcloud.personnel.positioning.persistence.repository.PersonnelMatchRepository;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;

import java.util.Arrays;
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.anyMap;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

class FindsStaffMappingSyncServiceTest {
    private final ObjectMapper objectMapper = new ObjectMapper();
    private FindsOpenApiClient findsOpenApiClient;
    private PositionPersonLocalLookupService localLookupService;
    private PersonnelMatchRepository personnelMatchRepository;
    private FindsCorpMappingService corpMappingService;
    private FindsStaffMappingSyncService service;

    @BeforeEach
    void setUp() {
        findsOpenApiClient = mock(FindsOpenApiClient.class);
        localLookupService = mock(PositionPersonLocalLookupService.class);
        personnelMatchRepository = mock(PersonnelMatchRepository.class);
        corpMappingService = mock(FindsCorpMappingService.class);
        service = new FindsStaffMappingSyncService(
                findsOpenApiClient, localLookupService, personnelMatchRepository, corpMappingService);
    }

    @Test
    void idCardHasPriorityOverStaffNumber() throws Exception {
        stubFindsStaff("F001", "张三", "ID-001");
        when(localLookupService.findAllPeople()).thenReturn(Arrays.asList(
                person(1L, "OTHER", "张三", "13800000001", "ID-001"),
                person(2L, "F001", "李四", "13800000002", "ID-002")));

        service.syncAll();

        Map<String, Object> values = insertedPersonnelValues();
        assertEquals(1L, values.get("localUserId"));
        assertEquals("MATCHED", values.get("matchStatus"));
        assertEquals("ID_CARD", values.get("matchType"));
        verify(corpMappingService).resolve(eq("FINDS"), any(), any(), any(), any());
    }

    @Test
    void duplicateNameIsAmbiguous() throws Exception {
        stubFindsStaff("F404", "同名人员", null);
        when(localLookupService.findAllPeople()).thenReturn(Arrays.asList(
                person(3L, "U003", "同名人员", "13800000003", "ID-003"),
                person(4L, "U004", "同名人员", "13800000004", "ID-004")));

        service.syncAll();

        Map<String, Object> values = insertedPersonnelValues();
        assertNull(values.get("localUserId"));
        assertEquals("AMBIGUOUS", values.get("matchStatus"));
        assertNull(values.get("matchType"));
    }

    private void stubFindsStaff(String staffNo, String name, String idCardNo) throws Exception {
        String idCardJson = idCardNo == null ? "null" : "\"" + idCardNo + "\"";
        when(findsOpenApiClient.postFailFast(eq("finds.staff.list"), anyMap())).thenReturn(
                objectMapper.readTree("{\"code\":200,\"data\":{\"total\":1,\"data\":[{"
                        + "\"trackNo\":\"" + staffNo + "\",\"staffName\":\"" + name
                        + "\",\"idCardNo\":" + idCardJson + "}]}}"));
    }

    private PositionPersonLocalLookupService.LocalPerson person(Long id, String username, String name,
                                                                 String phone, String idCardNo) {
        PositionPersonLocalLookupService.LocalPerson person = new PositionPersonLocalLookupService.LocalPerson();
        person.setUserId(id);
        person.setLocalStaffNo(username);
        person.setStaffName(name);
        person.setMobileNo(phone);
        person.setIdCardNo(idCardNo);
        return person;
    }

    private Map<String, Object> insertedPersonnelValues() {
        ArgumentCaptor<Map<String, Object>> captor = ArgumentCaptor.forClass(Map.class);
        verify(personnelMatchRepository).upsert(captor.capture());
        return captor.getValue();
    }
}
