package com.yaoai.domain.mapper;

import com.yaoai.domain.entity.Storyboard;
import org.h2.jdbcx.JdbcDataSource;
import org.apache.ibatis.mapping.Environment;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory;
import org.junit.jupiter.api.Test;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.Statement;
import java.util.List;

import static org.junit.jupiter.api.Assertions.assertEquals;

class StoryboardMapperTest {

    @Test
    void findMissingVideoPromptByEpisodeReturnsOnlyMatchingRowsInSequenceOrder() throws Exception {
        JdbcDataSource dataSource = new JdbcDataSource();
        dataSource.setURL("jdbc:h2:mem:storyboard_mapper;MODE=MySQL;DB_CLOSE_DELAY=-1");
        dataSource.setUser("sa");
        dataSource.setPassword("");

        createSchema(dataSource);
        seedStoryboards(dataSource);

        Environment environment = new Environment("test", new JdbcTransactionFactory(), dataSource);
        Configuration configuration = new Configuration(environment);
        configuration.setMapUnderscoreToCamelCase(true);
        configuration.addMapper(StoryboardMapper.class);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(configuration);

        try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
            StoryboardMapper mapper = sqlSession.getMapper(StoryboardMapper.class);

            List<Storyboard> storyboards = mapper.findMissingVideoPromptByEpisode(10L, 20L);

            assertEquals(2, storyboards.size());
            assertEquals(List.of(102L, 101L), storyboards.stream().map(Storyboard::getId).toList());
            assertEquals(List.of("scene-2", "scene-1"), storyboards.stream().map(Storyboard::getSceneRef).toList());
        }
    }

    private static void createSchema(JdbcDataSource dataSource) throws Exception {
        try (Connection connection = dataSource.getConnection();
             Statement statement = connection.createStatement()) {
            statement.execute("""
                    CREATE TABLE storyboards (
                        id BIGINT NOT NULL PRIMARY KEY,
                        episode_id BIGINT NOT NULL,
                        tenant_id BIGINT NOT NULL,
                        sequence_num INT NOT NULL,
                        scene_ref VARCHAR(128),
                        video_prompt LONGTEXT
                    )
                    """);
        }
    }

    private static void seedStoryboards(JdbcDataSource dataSource) throws Exception {
        try (Connection connection = dataSource.getConnection();
             PreparedStatement statement = connection.prepareStatement("""
                     INSERT INTO storyboards (id, episode_id, tenant_id, sequence_num, scene_ref, video_prompt)
                     VALUES (?, ?, ?, ?, ?, ?)
                     """)) {
            insertStoryboard(statement, 101L, 10L, 20L, 2, "scene-1", null);
            insertStoryboard(statement, 102L, 10L, 20L, 1, "scene-2", "   ");
            insertStoryboard(statement, 103L, 10L, 20L, 3, "scene-3", "Ready for video");
            insertStoryboard(statement, 104L, 10L, 21L, 4, "scene-4", null);
        }
    }

    private static void insertStoryboard(PreparedStatement statement,
                                         Long id,
                                         Long episodeId,
                                         Long tenantId,
                                         int sequenceNum,
                                         String sceneRef,
                                         String videoPrompt) throws Exception {
        statement.setLong(1, id);
        statement.setLong(2, episodeId);
        statement.setLong(3, tenantId);
        statement.setInt(4, sequenceNum);
        statement.setString(5, sceneRef);
        statement.setString(6, videoPrompt);
        statement.executeUpdate();
    }
}
