package dev.privacyllc.period.core.data

import dev.privacyllc.period.core.database.entity.NotYetObservationEntity
import dev.privacyllc.period.core.database.entity.PeriodRecordEntity
import dev.privacyllc.period.core.database.entity.PredictionRecordEntity
import dev.privacyllc.period.core.database.entity.SpottingRecordEntity
import dev.privacyllc.period.domain.cycle.PeriodRecord
import dev.privacyllc.period.domain.cycle.PeriodRecordSource
import dev.privacyllc.period.domain.cycle.SpottingRecord
import dev.privacyllc.period.domain.prediction.ConfidenceLabel
import dev.privacyllc.period.domain.prediction.NotYetObservation
import dev.privacyllc.period.domain.prediction.Prediction
import java.time.Instant

/**
 * Entity ⇄ domain, and this file is the only place either type meets the other.
 *
 * The mapping is not ceremony. `domain` modules are pure-JVM modules that cannot see
 * the Android SDK, which is what makes the prediction engine testable in a
 * second rather than on an emulator — and returning a Room entity from a
 * repository would drag `androidx.room` onto the compile classpath of every
 * caller and quietly end that.
 *
 * Enums cross as their names. An unrecognised name falls back rather than
 * throwing: a row written by a newer build must not crash an older one, and a
 * cycle history is worth more than strictness about a label.
 */

internal fun PeriodRecordEntity.toDomain() = PeriodRecord(
    id = id,
    startDate = startDate,
    endDate = endDate,
    source = PeriodRecordSource.entries.firstOrNull { it.name == source } ?: PeriodRecordSource.MANUAL,
    isConfirmed = isConfirmed,
)

internal fun PeriodRecord.toEntity(createdAt: Instant, updatedAt: Instant) = PeriodRecordEntity(
    id = id,
    startDate = startDate,
    endDate = endDate,
    createdAt = createdAt,
    updatedAt = updatedAt,
    source = source.name,
    isConfirmed = isConfirmed,
)

internal fun SpottingRecordEntity.toDomain() = SpottingRecord(id = id, date = date)

internal fun NotYetObservationEntity.toDomain() = NotYetObservation(date = date, predictionId = predictionId)

internal fun PredictionRecordEntity.toDomain() = Prediction(
    mostLikelyStartDate = predictedStartDate,
    windowStart = predictedWindowStart,
    windowEnd = predictedWindowEnd,
    confidenceScore = confidenceScore,
    confidenceLabel = ConfidenceLabel.entries.firstOrNull { it.name == confidenceLabel } ?: ConfidenceLabel.LOW,
    modelVersion = modelVersion,
)

internal fun Prediction.toEntity(generatedAt: Instant, basedOnPeriodId: Long?) = PredictionRecordEntity(
    generatedAt = generatedAt,
    basedOnLastConfirmedPeriodId = basedOnPeriodId,
    predictedStartDate = mostLikelyStartDate,
    predictedWindowStart = windowStart,
    predictedWindowEnd = windowEnd,
    estimatedOvulationDate = null,
    fertileWindowStart = null,
    fertileWindowEnd = null,
    confidenceScore = confidenceScore,
    confidenceLabel = confidenceLabel.name,
    modelVersion = modelVersion,
    actualStartDate = null,
    absoluteErrorDays = null,
)
