package study.testing.slices;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.UUID;

import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.jdbc.test.autoconfigure.AutoConfigureTestDatabase;
import org.springframework.boot.jdbc.test.autoconfigure.JdbcTest;
import org.springframework.context.ApplicationContext;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.test.context.DynamicPropertyRegistry;
import org.springframework.test.context.DynamicPropertySource;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.DispatcherServlet;

/**
 * @JdbcTest + replace=NONE 连真实本机 MySQL（独有合成库）：
 * 数据层在场、Web 层缺席；同时验证 @JdbcTest 默认事务回滚。
 */
@JdbcTest
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
class JdbcSliceTest {

    static final String DB = "u25_" + UUID.randomUUID().toString().replace("-", "");
    static final String BASE = "jdbc:mysql://127.0.0.1:3306/?sslMode=DISABLED&allowPublicKeyRetrieval=true";

    @Autowired
    JdbcTemplate jdbc;

    @Autowired
    ApplicationContext context;

    @DynamicPropertySource
    static void syntheticDatabase(DynamicPropertyRegistry registry) {
        try (Connection connection = DriverManager.getConnection(BASE, "root", "");
                Statement statement = connection.createStatement()) {
            statement.executeUpdate("CREATE DATABASE IF NOT EXISTS `" + DB + "`");
            statement.executeUpdate("CREATE TABLE IF NOT EXISTS `" + DB + "`.u25_slice_t (id INT PRIMARY KEY, val VARCHAR(64))");
        } catch (SQLException e) {
            throw new IllegalStateException("本机 MySQL 127.0.0.1:3306 root 空密码不可用或建库失败", e);
        }
        registry.add("spring.datasource.url", () -> "jdbc:mysql://127.0.0.1:3306/" + DB + "?sslMode=DISABLED&allowPublicKeyRetrieval=true");
        registry.add("spring.datasource.username", () -> "root");
        registry.add("spring.datasource.password", () -> "");
    }

    @Test
    @Order(1)
    void dataLayerPresentWebLayerAbsent() {
        org.junit.jupiter.api.Assertions.assertEquals(1, context.getBeansOfType(JdbcTemplate.class).size());
        org.junit.jupiter.api.Assertions.assertTrue(context.getBeansOfType(OrderService.class).isEmpty(), "JDBC 切片不扫业务 Service");
        org.junit.jupiter.api.Assertions.assertTrue(context.getBeansWithAnnotation(RestController.class).isEmpty(), "JDBC 切片不装控制器");
        org.junit.jupiter.api.Assertions.assertTrue(context.getBeansOfType(DispatcherServlet.class).isEmpty(), "JDBC 切片没有 DispatcherServlet");
        System.out.println("U25OBSERVE jdbc-slice jdbcBeans=1 controllerBeans=0 dispatcherServletBeans=0");
    }

    @Test
    @Order(2)
    void realMySqlRoundTripInsideSlice() {
        jdbc.update("INSERT INTO u25_slice_t (id, val) VALUES (1, 'slice-row')");
        int inTx = jdbc.queryForObject("SELECT COUNT(*) FROM u25_slice_t", Integer.class);
        org.junit.jupiter.api.Assertions.assertEquals(1, inTx, "同一测试事务内可见");
        System.out.println("U25OBSERVE jdbc-slice insertVisibleInTx=" + inTx);
    }

    @Test
    @Order(3)
    void jdbcSliceAlsoRollsBackByDefault() {
        int afterRollback = jdbc.queryForObject("SELECT COUNT(*) FROM u25_slice_t", Integer.class);
        org.junit.jupiter.api.Assertions.assertEquals(0, afterRollback, "@JdbcTest 默认回滚上一切片测试方法的事务");
        System.out.println("U25OBSERVE jdbc-slice rowsAfterRollback=" + afterRollback);
    }

    @AfterAll
    static void dropSyntheticDatabase() throws SQLException {
        try (Connection connection = DriverManager.getConnection(BASE, "root", "");
                Statement statement = connection.createStatement()) {
            statement.executeUpdate("DROP DATABASE `" + DB + "`");
            System.out.println("U25OBSERVE jdbc-slice syntheticDatabaseDropped=" + DB);
        }
    }
}
