package com.gxwebsoft.house.ai;

import com.gxwebsoft.house.entity.HouseAiIntent;
import com.gxwebsoft.house.entity.HouseInfo;
import com.gxwebsoft.house.param.HouseInfoParam;
import com.gxwebsoft.house.service.HouseInfoService;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.test.util.ReflectionTestUtils;

import java.math.BigDecimal;
import java.util.Arrays;
import java.util.Collections;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.when;

@ExtendWith(MockitoExtension.class)
class HouseAiSearchEngineTest {

    @Mock
    private HouseInfoService houseInfoService;

    private HouseAiSearchEngine searchEngine;

    @BeforeEach
    void setUp() {
        searchEngine = new HouseAiSearchEngine();
        ReflectionTestUtils.setField(searchEngine, "houseInfoService", houseInfoService);
    }

    @Test
    void requestedUnknownFieldCannotBecomeExactOrCandidate() {
        HouseAiIntent intent = baseIntent();
        intent.setParkingAvailable(true);
        HouseInfo unknownParking = house(1, 2800, null);
        when(houseInfoService.listRel(any(HouseInfoParam.class))).thenReturn(Collections.singletonList(unknownParking));

        HouseAiSearchResult result = searchEngine.search(intent, "需要停车", 2001);

        assertEquals(HouseAiMatchTypes.NONE, result.getMatchType());
        assertEquals(0, result.getHouses().size());
    }

    @Test
    void candidateKeepsCustomerRequiredConditionWhileRelaxingBudgetWithinLimit() {
        HouseAiIntent intent = baseIntent();
        intent.setMonthlyRentMax(new BigDecimal("3000"));
        intent.setParkingAvailable(true);
        intent.setRequiredFields(Collections.singletonList("parkingAvailable"));
        HouseInfo wrongParking = house(1, 2800, false);
        HouseInfo overBudgetButParking = house(2, 3300, true);
        when(houseInfoService.listRel(any(HouseInfoParam.class)))
            .thenReturn(Arrays.asList(wrongParking, overBudgetButParking));

        HouseAiSearchResult result = searchEngine.search(intent, "月租 3000，必须停车", 2001);

        assertEquals(HouseAiMatchTypes.APPROXIMATE, result.getMatchType());
        assertEquals(1, result.getHouses().size());
        assertEquals(Integer.valueOf(2), result.getHouses().get(0).getHouseId());
    }

    @Test
    void budgetBeyondTwentyPercentIsNotCandidate() {
        HouseAiIntent intent = baseIntent();
        intent.setMonthlyRentMax(new BigDecimal("3000"));
        HouseInfo overBudget = house(1, 3601, true);
        when(houseInfoService.listRel(any(HouseInfoParam.class))).thenReturn(Collections.singletonList(overBudget));

        HouseAiSearchResult result = searchEngine.search(intent, "月租 3000", 2001);

        assertEquals(HouseAiMatchTypes.NONE, result.getMatchType());
    }

    private HouseAiIntent baseIntent() {
        HouseAiIntent intent = new HouseAiIntent();
        intent.setCityKeyword("南宁");
        intent.setTradeType("rent");
        return intent;
    }

    private HouseInfo house(int id, int rent, Boolean parking) {
        HouseInfo house = new HouseInfo();
        house.setHouseId(id);
        house.setHouseTitle("南宁房源" + id);
        house.setCity("南宁");
        house.setMonthlyRent(new BigDecimal(rent));
        house.setParkingAvailable(parking);
        house.setStatus(0);
        return house;
    }
}
