package org.raddatz.familienarchiv.importing;

import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import org.raddatz.familienarchiv.exception.DomainException;

import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;

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

class CanonicalSheetReaderTest {

    @Test
    void readRows_mapsCellsByHeaderName(@TempDir Path tempDir) throws Exception {
        Path xlsx = write(tempDir, List.of("index", "file"), List.of(List.of("W-0001", "scan.pdf")));

        List<CanonicalSheetReader.Row> rows = CanonicalSheetReader.readRows(xlsx.toFile(), List.of("index", "file"));

        assertThat(rows).hasSize(1);
        assertThat(rows.get(0).get("index")).isEqualTo("W-0001");
        assertThat(rows.get(0).get("file")).isEqualTo("scan.pdf");
    }

    @Test
    void readRows_throwsBadRequest_whenRequiredHeaderMissing(@TempDir Path tempDir) throws Exception {
        Path xlsx = write(tempDir, List.of("index"), List.of(List.of("W-0001")));

        assertThatThrownBy(() -> CanonicalSheetReader.readRows(xlsx.toFile(), List.of("index", "file")))
                .isInstanceOf(DomainException.class)
                .hasMessageContaining("file");
    }

    @Test
    void get_returnsEmptyString_forBlankCell(@TempDir Path tempDir) throws Exception {
        Path xlsx = write(tempDir, List.of("index", "file"), List.of(List.of("W-0001", "")));

        List<CanonicalSheetReader.Row> rows = CanonicalSheetReader.readRows(xlsx.toFile(), List.of("index", "file"));

        assertThat(rows.get(0).get("file")).isEmpty();
    }

    @Test
    void get_returnsEmptyString_forUnknownColumn(@TempDir Path tempDir) throws Exception {
        Path xlsx = write(tempDir, List.of("index"), List.of(List.of("W-0001")));

        List<CanonicalSheetReader.Row> rows = CanonicalSheetReader.readRows(xlsx.toFile(), List.of("index"));

        assertThat(rows.get(0).get("does_not_exist")).isEmpty();
    }

    @Test
    void get_returnsEmptyString_forTrailingColumns_whenRowShorterThanHeader(@TempDir Path tempDir) throws Exception {
        // POI omits trailing empty cells, so a real-world artifact row can be narrower than
        // the header. The missing columns must read as "" rather than throwing.
        Path xlsx = write(tempDir,
                List.of("index", "file", "summary"),
                List.of(List.of("W-0001")));

        List<CanonicalSheetReader.Row> rows = CanonicalSheetReader.readRows(xlsx.toFile(), List.of("index", "file", "summary"));

        assertThat(rows.get(0).get("index")).isEqualTo("W-0001");
        assertThat(rows.get(0).get("file")).isEmpty();
        assertThat(rows.get(0).get("summary")).isEmpty();
    }

    @Test
    void splitList_splitsOnPipe() {
        assertThat(CanonicalSheetReader.splitList("a|b|c")).containsExactly("a", "b", "c");
    }

    @Test
    void splitList_returnsEmptyList_forBlank() {
        assertThat(CanonicalSheetReader.splitList("")).isEmpty();
        assertThat(CanonicalSheetReader.splitList("   ")).isEmpty();
    }

    @Test
    void splitList_returnsSingleElement_whenNoPipe() {
        assertThat(CanonicalSheetReader.splitList("solo")).containsExactly("solo");
    }

    @Test
    void splitList_trimsAndDropsEmptySegments() {
        assertThat(CanonicalSheetReader.splitList("a| |b")).containsExactly("a", "b");
    }

    private Path write(Path dir, List<String> headers, List<List<String>> dataRows) throws Exception {
        Path xlsx = dir.resolve("sheet.xlsx");
        try (XSSFWorkbook wb = new XSSFWorkbook()) {
            Sheet sheet = wb.createSheet("Sheet1");
            Row header = sheet.createRow(0);
            for (int i = 0; i < headers.size(); i++) {
                header.createCell(i).setCellValue(headers.get(i));
            }
            for (int r = 0; r < dataRows.size(); r++) {
                Row row = sheet.createRow(r + 1);
                List<String> values = dataRows.get(r);
                for (int c = 0; c < values.size(); c++) {
                    row.createCell(c).setCellValue(values.get(c));
                }
            }
            try (OutputStream out = Files.newOutputStream(xlsx)) {
                wb.write(out);
            }
        }
        return xlsx;
    }
}
