package com.writeoff.module.system.service;

import com.writeoff.common.exception.BusinessException;
import com.writeoff.module.system.dto.CreateUserDelegationRequest;
import com.writeoff.security.AuthContext;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import org.springframework.jdbc.core.JdbcTemplate;

import java.lang.reflect.Field;
class UserDelegationServiceValidationTest {

    @AfterEach
    void tearDown() {
        AuthContext.clear();
    }

    @Test
    void shouldRejectSelfDelegation() throws Exception {
        JdbcTemplate jdbcTemplate = Mockito.mock(JdbcTemplate.class);
        UserDelegationService service = new UserDelegationService(jdbcTemplate);
        AuthContext.set(1L, 1L);

        Mockito.when(jdbcTemplate.queryForObject(
                Mockito.eq("SELECT COUNT(1) FROM sys_user WHERE tenant_id=? AND id=? AND is_deleted=0"),
                Mockito.eq(Integer.class),
                Mockito.eq(1L),
                Mockito.eq(10L)
        )).thenReturn(1);

        CreateUserDelegationRequest request = new CreateUserDelegationRequest();
        setField(request, "delegateUserId", 10L);
        setField(request, "effectiveFrom", "2026-03-10 10:00:00");
        setField(request, "effectiveTo", "2026-03-10 18:00:00");

        Assertions.assertThrows(BusinessException.class, () -> service.create(10L, request));
    }

    @Test
    void shouldRejectInvalidTimeWindow() throws Exception {
        JdbcTemplate jdbcTemplate = Mockito.mock(JdbcTemplate.class);
        UserDelegationService service = new UserDelegationService(jdbcTemplate);
        AuthContext.set(1L, 1L);

        Mockito.when(jdbcTemplate.queryForObject(
                Mockito.eq("SELECT COUNT(1) FROM sys_user WHERE tenant_id=? AND id=? AND is_deleted=0"),
                Mockito.eq(Integer.class),
                Mockito.eq(1L),
                Mockito.eq(10L)
        )).thenReturn(1);
        Mockito.when(jdbcTemplate.queryForObject(
                Mockito.eq("SELECT COUNT(1) FROM sys_user WHERE tenant_id=? AND id=? AND is_deleted=0"),
                Mockito.eq(Integer.class),
                Mockito.eq(1L),
                Mockito.eq(20L)
        )).thenReturn(1);

        CreateUserDelegationRequest request = new CreateUserDelegationRequest();
        setField(request, "delegateUserId", 20L);
        setField(request, "effectiveFrom", "2026-03-10 18:00:00");
        setField(request, "effectiveTo", "2026-03-10 10:00:00");

        Assertions.assertThrows(BusinessException.class, () -> service.create(10L, request));
        Mockito.verify(jdbcTemplate, Mockito.never()).update(
                Mockito.contains("INSERT INTO user_delegation"),
                Mockito.any(),
                Mockito.any(),
                Mockito.any(),
                Mockito.any(),
                Mockito.any(),
                Mockito.any(),
                Mockito.any(),
                Mockito.any(),
                Mockito.any()
        );
    }

    private static void setField(Object target, String fieldName, Object value) throws Exception {
        Field field = target.getClass().getDeclaredField(fieldName);
        field.setAccessible(true);
        field.set(target, value);
    }
}
