package org.raddatz.familienarchiv.document.transcription;

import org.junit.jupiter.api.Test;
import org.raddatz.familienarchiv.PostgresContainerConfig;
import org.raddatz.familienarchiv.document.transcription.CompletionStatsRow;
import org.raddatz.familienarchiv.config.FlywayConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.data.jpa.test.autoconfigure.DataJpaTest;
import org.springframework.boot.jdbc.test.autoconfigure.AutoConfigureTestDatabase;
import org.springframework.context.annotation.Import;
import org.springframework.test.context.jdbc.Sql;

import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.stream.Collectors;

import static org.assertj.core.api.Assertions.assertThat;

@DataJpaTest
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
@Import({PostgresContainerConfig.class, FlywayConfig.class})
class TranscriptionBlockRepositoryIntegrationTest {

    static final UUID DOC_A = UUID.fromString("aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa");
    static final UUID DOC_B = UUID.fromString("bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb");
    static final UUID ANN_A = UUID.fromString("cccccccc-cccc-cccc-cccc-cccccccccccc");
    static final UUID ANN_B = UUID.fromString("dddddddd-dddd-dddd-dddd-dddddddddddd");

    @Autowired TranscriptionBlockRepository repository;

    @Test
    @Sql(statements = {
        "INSERT INTO documents (id, title, original_filename, status) VALUES ('aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa', 'Doc A', 'a.pdf', 'PLACEHOLDER')",
        "INSERT INTO document_annotations (id, document_id, page_number, x, y, width, height, color) VALUES ('cccccccc-cccc-cccc-cccc-cccccccccccc', 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa', 1, 0, 0, 1, 1, '#fff')",
        "INSERT INTO transcription_blocks (annotation_id, document_id, sort_order, reviewed) VALUES ('cccccccc-cccc-cccc-cccc-cccccccccccc', 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa', 0, true)",
        "INSERT INTO transcription_blocks (annotation_id, document_id, sort_order, reviewed) VALUES ('cccccccc-cccc-cccc-cccc-cccccccccccc', 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa', 1, true)"
    })
    void findCompletionStats_returns_100_when_all_blocks_reviewed() {
        List<CompletionStatsRow> rows = repository.findCompletionStatsForDocuments(List.of(DOC_A));

        assertThat(rows).hasSize(1);
        assertThat(rows.get(0).getDocumentId()).isEqualTo(DOC_A);
        assertThat(rows.get(0).getCompletionPercentage()).isEqualTo(100);
    }

    @Test
    @Sql(statements = {
        "INSERT INTO documents (id, title, original_filename, status) VALUES ('aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa', 'Doc A', 'a.pdf', 'PLACEHOLDER')",
        "INSERT INTO document_annotations (id, document_id, page_number, x, y, width, height, color) VALUES ('cccccccc-cccc-cccc-cccc-cccccccccccc', 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa', 1, 0, 0, 1, 1, '#fff')",
        "INSERT INTO transcription_blocks (annotation_id, document_id, sort_order, reviewed) VALUES ('cccccccc-cccc-cccc-cccc-cccccccccccc', 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa', 0, false)",
        "INSERT INTO transcription_blocks (annotation_id, document_id, sort_order, reviewed) VALUES ('cccccccc-cccc-cccc-cccc-cccccccccccc', 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa', 1, false)"
    })
    void findCompletionStats_returns_0_when_no_blocks_reviewed() {
        List<CompletionStatsRow> rows = repository.findCompletionStatsForDocuments(List.of(DOC_A));

        assertThat(rows).hasSize(1);
        assertThat(rows.get(0).getCompletionPercentage()).isEqualTo(0);
    }

    @Test
    @Sql(statements = {
        "INSERT INTO documents (id, title, original_filename, status) VALUES ('aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa', 'Doc A', 'a.pdf', 'PLACEHOLDER')"
    })
    void findCompletionStats_returns_empty_when_document_has_no_blocks() {
        List<CompletionStatsRow> rows = repository.findCompletionStatsForDocuments(List.of(DOC_A));

        assertThat(rows).isEmpty();
    }

    @Test
    @Sql(statements = {
        "INSERT INTO documents (id, title, original_filename, status) VALUES ('aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa', 'Doc A', 'a.pdf', 'PLACEHOLDER')",
        "INSERT INTO document_annotations (id, document_id, page_number, x, y, width, height, color) VALUES ('cccccccc-cccc-cccc-cccc-cccccccccccc', 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa', 1, 0, 0, 1, 1, '#fff')",
        "INSERT INTO transcription_blocks (annotation_id, document_id, sort_order, reviewed) VALUES ('cccccccc-cccc-cccc-cccc-cccccccccccc', 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa', 0, true)",
        "INSERT INTO transcription_blocks (annotation_id, document_id, sort_order, reviewed) VALUES ('cccccccc-cccc-cccc-cccc-cccccccccccc', 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa', 1, false)",
        "INSERT INTO transcription_blocks (annotation_id, document_id, sort_order, reviewed) VALUES ('cccccccc-cccc-cccc-cccc-cccccccccccc', 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa', 2, false)",
        "INSERT INTO transcription_blocks (annotation_id, document_id, sort_order, reviewed) VALUES ('cccccccc-cccc-cccc-cccc-cccccccccccc', 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa', 3, false)"
    })
    void findCompletionStats_rounds_partial_completion_correctly() {
        List<CompletionStatsRow> rows = repository.findCompletionStatsForDocuments(List.of(DOC_A));

        assertThat(rows).hasSize(1);
        assertThat(rows.get(0).getCompletionPercentage()).isEqualTo(25);
    }

    @Test
    @Sql(statements = {
        "INSERT INTO documents (id, title, original_filename, status) VALUES ('aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa', 'Doc A', 'a.pdf', 'PLACEHOLDER')",
        "INSERT INTO documents (id, title, original_filename, status) VALUES ('bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb', 'Doc B', 'b.pdf', 'PLACEHOLDER')",
        "INSERT INTO document_annotations (id, document_id, page_number, x, y, width, height, color) VALUES ('cccccccc-cccc-cccc-cccc-cccccccccccc', 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa', 1, 0, 0, 1, 1, '#fff')",
        "INSERT INTO document_annotations (id, document_id, page_number, x, y, width, height, color) VALUES ('dddddddd-dddd-dddd-dddd-dddddddddddd', 'bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb', 1, 0, 0, 1, 1, '#fff')",
        "INSERT INTO transcription_blocks (annotation_id, document_id, sort_order, reviewed) VALUES ('cccccccc-cccc-cccc-cccc-cccccccccccc', 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa', 0, true)",
        "INSERT INTO transcription_blocks (annotation_id, document_id, sort_order, reviewed) VALUES ('dddddddd-dddd-dddd-dddd-dddddddddddd', 'bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb', 0, false)"
    })
    void findCompletionStats_handles_multiple_documents_in_one_call() {
        List<CompletionStatsRow> rows = repository.findCompletionStatsForDocuments(List.of(DOC_A, DOC_B));

        Map<UUID, Integer> byDoc = rows.stream()
                .collect(Collectors.toMap(CompletionStatsRow::getDocumentId, CompletionStatsRow::getCompletionPercentage));

        assertThat(byDoc).containsEntry(DOC_A, 100);
        assertThat(byDoc).containsEntry(DOC_B, 0);
    }

    @Test
    @Sql(statements = {
        "INSERT INTO documents (id, title, original_filename, status) VALUES ('aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa', 'Doc A', 'a.pdf', 'PLACEHOLDER')",
        "INSERT INTO document_annotations (id, document_id, page_number, x, y, width, height, color) VALUES ('cccccccc-cccc-cccc-cccc-cccccccccccc', 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa', 1, 0, 0, 1, 1, '#fff')",
        "INSERT INTO transcription_blocks (annotation_id, document_id, sort_order, reviewed) VALUES ('cccccccc-cccc-cccc-cccc-cccccccccccc', 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa', 0, false)"
    })
    void existsByDocumentId_returns_true_when_document_has_a_block() {
        assertThat(repository.existsByDocumentId(DOC_A)).isTrue();
    }

    @Test
    @Sql(statements = {
        "INSERT INTO documents (id, title, original_filename, status) VALUES ('aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa', 'Doc A', 'a.pdf', 'PLACEHOLDER')"
    })
    void existsByDocumentId_returns_false_when_document_has_no_blocks() {
        assertThat(repository.existsByDocumentId(DOC_A)).isFalse();
    }
}
