package com.mosquito.project.integration;

import com.mosquito.project.config.TestSecurityConfig;
import com.mosquito.project.permission.PermissionCheckService;
import com.mosquito.project.security.IntrospectionResponse;
import com.mosquito.project.security.UserIntrospectionService;
import com.mosquito.project.service.AuthService;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.TestInstance;
import org.mockito.Mockito;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.boot.test.util.TestPropertyValues;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Import;
import org.springframework.test.context.ContextConfiguration;

import java.time.Instant;
import java.util.List;

/**
 * 集成测试基类
 * 提供H2内存数据库和配置用于集成测试
 */
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
@ContextConfiguration(initializers = AbstractIntegrationTest.Initializer.class)
@Import(TestSecurityConfig.class)
abstract class AbstractIntegrationTest {

    @MockBean
    private UserIntrospectionService userIntrospectionService;

    @MockBean
    private PermissionCheckService permissionCheckService;

    @MockBean
    private AuthService authService;

    /**
     * Spring Boot测试属性初始化器
     */
    static class Initializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
        public void initialize(ConfigurableApplicationContext applicationContext) {
            TestPropertyValues.of(
                // H2内存数据库配置
                "spring.datasource.url=jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1;MODE=PostgreSQL",
                "spring.datasource.username=sa",
                "spring.datasource.password=",
                "spring.datasource.driver-class-name=org.h2.Driver",
                "spring.jpa.hibernate.ddl-auto=create-drop",
                "spring.jpa.show-sql=true",
                "spring.jpa.database-platform=org.hibernate.dialect.H2Dialect",
                
                // Redis配置
                "spring.redis.host=localhost",
                "spring.redis.port=6379",
                "spring.data.redis.host=localhost",
                "spring.data.redis.port=6379",
                
                // Flyway配置
                "spring.liquibase.enabled=false",
                "spring.flyway.enabled=false",
                
                // 日志配置
                "logging.level.com.mosquito.project=DEBUG",
                "logging.level.org.springframework.jdbc=DEBUG"
            ).applyTo(applicationContext.getEnvironment());
        }
    }

    /**
     * 等待测试环境准备就绪
     */
    @BeforeAll
    static void setUp() {
        System.out.println("集成测试环境准备就绪 - 使用H2内存数据库");
    }

    @BeforeEach
    void stubIntrospection() {
        IntrospectionResponse active = new IntrospectionResponse();
        active.setActive(true);
        active.setUserId("test-user");
        active.setTenantId("test-tenant");
        active.setRoles(List.of("test"));
        active.setScopes(List.of("api"));
        long now = Instant.now().getEpochSecond();
        active.setIat(now);
        active.setExp(now + 3600);
        active.setJti("test-jti");
        Mockito.when(userIntrospectionService.introspect(Mockito.anyString())).thenReturn(active);

        AuthService.TokenInfo tokenInfo = new AuthService.TokenInfo(10001L, Instant.now().plusSeconds(3600));
        Mockito.when(authService.validateToken(Mockito.anyString())).thenReturn(tokenInfo);

        AuthService.UserInfo userInfo = new AuthService.UserInfo(
            10001L,
            "integration-user",
            null,
            "集成测试用户",
            1L,
            List.of("ADMIN"),
            List.of("activity:create", "activity:view")
        );
        Mockito.when(authService.getUserById(Mockito.anyLong())).thenReturn(userInfo);

        // Mock权限检查服务，所有权限检查返回true
        Mockito.when(permissionCheckService.hasPermission(Mockito.anyLong(), Mockito.anyString())).thenReturn(true);
        Mockito.when(permissionCheckService.hasRole(Mockito.anyLong(), Mockito.anyString())).thenReturn(true);
        Mockito.when(permissionCheckService.getUserDataScope(Mockito.anyLong())).thenReturn("ALL");
    }
}
