@file:OptIn(ExperimentalSerializationApi::class)

package com.fabledsword.minstrel.models.wire

import kotlinx.serialization.EncodeDefault
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable

/**
 * Wire shapes for `POST /api/events`. The endpoint multiplexes four
 * variants on the `type` discriminator field, mirroring
 * `flutter_client/lib/api/endpoints/events.dart`.
 *
 * play_started returns the server-assigned play_event_id (nullable —
 * server may suppress under certain conditions); the other three
 * variants return 204-equivalent (no body).
 */

@Serializable
data class PlayStartedRequest(
    // Discriminator MUST stay on the wire. The app's Json has
    // encodeDefaults=false, so without this a `type` left at its
    // default is omitted entirely and the server 400s the event as
    // "unknown event type" — silently dropping every native play.
    @EncodeDefault(EncodeDefault.Mode.ALWAYS) val type: String = "play_started",
    @SerialName("track_id") val trackId: String,
    @SerialName("client_id") val clientId: String,
    val source: String? = null,
    // #1551: device class for context conditioning (server normalizes).
    @SerialName("device_class") val deviceClass: String? = null,
)

@Serializable
data class PlayStartedResponse(
    @SerialName("play_event_id") val playEventId: String? = null,
)

@Serializable
data class PlayEndedRequest(
    @EncodeDefault(EncodeDefault.Mode.ALWAYS) val type: String = "play_ended",
    @SerialName("play_event_id") val playEventId: String,
    @SerialName("duration_played_ms") val durationPlayedMs: Long,
)

@Serializable
data class PlaySkippedRequest(
    @EncodeDefault(EncodeDefault.Mode.ALWAYS) val type: String = "play_skipped",
    @SerialName("play_event_id") val playEventId: String,
    @SerialName("position_ms") val positionMs: Long,
)

@Serializable
data class PlayOfflineRequest(
    @EncodeDefault(EncodeDefault.Mode.ALWAYS) val type: String = "play_offline",
    @SerialName("track_id") val trackId: String,
    @SerialName("client_id") val clientId: String,
    val at: String,
    @SerialName("duration_played_ms") val durationPlayedMs: Long,
    val source: String? = null,
    // #1551: device class for context conditioning (server normalizes).
    @SerialName("device_class") val deviceClass: String? = null,
)
