package org.dromara.app.handler;

import cn.hutool.extra.spring.SpringUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.dromara.app.domain.bo.AppDeviceBo;
import org.dromara.app.domain.bo.AppWateringLogBo;
import org.dromara.app.domain.vo.AppDeviceVo;
import org.dromara.app.mapper.AppSchedulingDeviceMapper;
import org.dromara.app.service.IAppDeviceService;
import org.dromara.app.service.IAppWateringLogService;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.context.support.GenericApplicationContext;

import java.util.function.Supplier;

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

@ExtendWith(MockitoExtension.class)
@Tag("dev")
class KeyFinishHandlerTest {

    @Mock private IAppWateringLogService appWateringLogService;
    @Mock private IAppDeviceService appDeviceService;
    @Mock private AppSchedulingDeviceMapper schedulingDeviceMapper;
    @Mock private DeviceIdentityResolver deviceIdentityResolver;

    @Test
    void handle_setsDeviceWorkStatusIdleWhenKeyWateringFinished() {
        KeyFinishHandler handler = new KeyFinishHandler(
            appWateringLogService,
            appDeviceService,
            schedulingDeviceMapper,
            deviceIdentityResolver
        );
        AppDeviceVo device = new AppDeviceVo();
        device.setUserId(99L);

        when(deviceIdentityResolver.resolveDeviceNo("D01")).thenReturn("D01");
        when(appDeviceService.queryById("D01")).thenReturn(device);

        withJsonContext(() -> {
            handler.handle("D01", "{\"startTime\":\"2026-07-06 08:30:00\",\"durationMin\":10}");
            return null;
        });

        ArgumentCaptor<AppWateringLogBo> logCaptor = ArgumentCaptor.forClass(AppWateringLogBo.class);
        verify(appWateringLogService).confirmScheduleLog(logCaptor.capture());
        assertThat(logCaptor.getValue().getStatus()).isEqualTo("0");
        assertThat(logCaptor.getValue().getTriggerType()).isEqualTo("1");

        ArgumentCaptor<AppDeviceBo> deviceCaptor = ArgumentCaptor.forClass(AppDeviceBo.class);
        verify(appDeviceService).updateByBo(deviceCaptor.capture());
        AppDeviceBo updateBo = deviceCaptor.getValue();
        assertThat(updateBo.getDeviceNo()).isEqualTo("D01");
        assertThat(updateBo.getWorkStatus()).isEqualTo("0");
    }

    private <T> T withJsonContext(Supplier<T> action) {
        try (GenericApplicationContext applicationContext = new GenericApplicationContext()) {
            applicationContext.registerBean(ObjectMapper.class, (Supplier<ObjectMapper>) ObjectMapper::new);
            applicationContext.refresh();
            new SpringUtil().setApplicationContext(applicationContext);
            return action.get();
        }
    }
}
