package at.procon.dip.search.repository;

import at.procon.dip.domain.access.DocumentVisibility;
import at.procon.dip.domain.document.DocumentFamily;
import at.procon.dip.domain.document.DocumentType;
import at.procon.dip.domain.document.RepresentationType;
import at.procon.dip.search.dto.SearchEngineType;
import at.procon.dip.search.dto.SearchHit;
import at.procon.dip.search.dto.SearchMatchField;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.springframework.jdbc.core.RowMapper;

final class SearchHitRowMapper implements RowMapper<SearchHit> {

    private final SearchEngineType engineType;
    private final SearchMatchField defaultField;

    SearchHitRowMapper(SearchEngineType engineType, SearchMatchField defaultField) {
        this.engineType = engineType;
        this.defaultField = defaultField;
    }

    @Override
    public SearchHit mapRow(ResultSet rs, int rowNum) throws SQLException {
        String matchedField = safeGetString(rs, "matched_field");
        return SearchHit.builder()
                .documentId(rs.getObject("document_id", java.util.UUID.class))
                .representationId(rs.getObject("representation_id", java.util.UUID.class))
                .documentType(DocumentType.valueOf(rs.getString("document_type")))
                .documentFamily(DocumentFamily.valueOf(rs.getString("document_family")))
                .visibility(DocumentVisibility.valueOf(rs.getString("visibility")))
                .title(safeGetString(rs, "title"))
                .summary(safeGetString(rs, "summary"))
                .languageCode(safeGetString(rs, "language_code"))
                .mimeType(safeGetString(rs, "mime_type"))
                .representationType(parseRepresentationType(safeGetString(rs, "representation_type")))
                .primaryRepresentation(safeGetBoolean(rs, "is_primary"))
                .chunkIndex(safeGetInteger(rs, "chunk_index"))
                .chunkStartOffset(safeGetInteger(rs, "chunk_start_offset"))
                .chunkEndOffset(safeGetInteger(rs, "chunk_end_offset"))
                .primaryEngine(engineType)
                .matchedField(matchedField == null || matchedField.isBlank()
                        ? defaultField
                        : SearchMatchField.valueOf(matchedField))
                .snippet(safeGetString(rs, "snippet"))
                .rawScore(rs.getDouble("score"))
                .createdAt(rs.getObject("created_at", java.time.OffsetDateTime.class))
                .updatedAt(rs.getObject("updated_at", java.time.OffsetDateTime.class))
                .build();
    }

    private String safeGetString(ResultSet rs, String column) {
        try {
            return rs.getString(column);
        } catch (SQLException ignore) {
            return null;
        }
    }

    private Integer safeGetInteger(ResultSet rs, String column) {
        try {
            int value = rs.getInt(column);
            return rs.wasNull() ? null : value;
        } catch (SQLException ignore) {
            return null;
        }
    }

    private boolean safeGetBoolean(ResultSet rs, String column) {
        try {
            return rs.getBoolean(column) && !rs.wasNull();
        } catch (SQLException ignore) {
            return false;
        }
    }

    private RepresentationType parseRepresentationType(String value) {
        return value == null || value.isBlank() ? null : RepresentationType.valueOf(value);
    }
}
