package dev.mokksy.aimocks.openai.moderation

import dev.mokksy.aimocks.core.AbstractResponseSpecification
import dev.mokksy.aimocks.openai.model.moderation.CreateModerationRequest
import dev.mokksy.aimocks.openai.model.moderation.InputType
import dev.mokksy.aimocks.openai.model.moderation.InputType.TEXT
import dev.mokksy.aimocks.openai.model.moderation.Moderation
import dev.mokksy.aimocks.openai.model.moderation.ModerationCategory
import dev.mokksy.aimocks.openai.model.moderation.ModerationResult
import kotlin.time.Duration

/**
 * Response specification for OpenAI Moderation endpoint.
 *
 * @see <a href="https://platform.openai.com/docs/api-reference/moderations/object">Moderation Object</a>
 */
public class OpenaiModerationResponseSpecification(
    delay: Duration = Duration.ZERO,
) : AbstractResponseSpecification<CreateModerationRequest, Moderation>(
        delay = delay,
    ) {
    public var id: String? = null
    public var model: String = "omni-moderation-latest"
    public var flagged: Boolean = false
    public val categories: MutableMap<ModerationCategory, Boolean> = mutableMapOf()

    @Suppress("MagicNumber")
    public val categoryScores: MutableMap<ModerationCategory, Double> = mutableMapOf()

    /**
     * A list of the categories along with the input type(s) that the score applies to.
     */
    public val categoryAppliedInputTypes: MutableMap<ModerationCategory, List<InputType>> =
        mutableMapOf()

    init {
        // set default values
        category(name = "harassment", score = 0.0, inputTypes = listOf(TEXT))
        category(name = "harassment/threatening", score = 0.0, inputTypes = listOf(TEXT))
        category(name = "sexual", score = 0.0, inputTypes = listOf(TEXT))
        category(name = "hate", score = 0.0, inputTypes = listOf(TEXT))
        category(name = "hate/threatening", score = 0.0, inputTypes = listOf(TEXT))
        category(name = "illicit", score = 0.0, inputTypes = listOf(TEXT))
        category(name = "illicit/violent", score = 0.0, inputTypes = listOf(TEXT))
        category(name = "self-harm/intent", score = 0.0, inputTypes = listOf(TEXT))
        category(name = "self-harm/instructions", score = 0.0, inputTypes = listOf(TEXT))
        category(name = "self-harm", score = 0.0, inputTypes = listOf(TEXT))
        category(name = "sexual/minors", score = 0.0, inputTypes = listOf(TEXT))
        category(name = "violence", score = 0.0, inputTypes = listOf(TEXT))
        category(name = "violence/graphic", score = 0.0, inputTypes = listOf(InputType.IMAGE))
    }

    public fun model(value: String): OpenaiModerationResponseSpecification =
        apply { this.model = value }

    public fun flagged(value: Boolean): OpenaiModerationResponseSpecification =
        apply { this.flagged = value }

    public fun category(
        name: String,
        value: Boolean,
    ): OpenaiModerationResponseSpecification =
        apply {
            this.categories[ModerationCategory(name)] = value
        }

    public fun category(
        name: ModerationCategory,
        score: Double,
        inputTypes: List<InputType> = listOf(TEXT),
    ): OpenaiModerationResponseSpecification =
        apply {
            this.categories[name] = score > 0.0
            this.categoryScores[name] = score
            this.categoryAppliedInputTypes[name] = inputTypes
        }

    public fun category(
        name: String,
        score: Double,
        inputTypes: List<InputType> = listOf(TEXT),
    ): OpenaiModerationResponseSpecification =
        category(name = ModerationCategory(name), score = score, inputTypes = inputTypes)

    public fun score(
        name: ModerationCategory,
        value: Double,
    ): OpenaiModerationResponseSpecification =
        apply {
            this.categoryScores[name] = value
        }

    public fun appliedInputTypes(
        name: ModerationCategory,
        value: List<InputType>,
    ): OpenaiModerationResponseSpecification =
        apply {
            this.categoryAppliedInputTypes[name] = value
        }

    internal fun toResult(): ModerationResult =
        ModerationResult(
            flagged = flagged,
            categories = categories.toMap(),
            categoryScores = categoryScores.toMap(),
            categoryAppliedInputTypes = categoryAppliedInputTypes.toMap(),
        )
}
