package com.atridad.ascently.data.format

import com.atridad.ascently.data.model.*
import kotlinx.serialization.Serializable

// Root structure for Ascently backup data
@Serializable
data class ClimbDataBackup(
    val exportedAt: String,
    val version: String = "2.0",
    val formatVersion: String = "2.0",
    val gyms: List<BackupGym>,
    val problems: List<BackupProblem>,
    val sessions: List<BackupClimbSession>,
    val attempts: List<BackupAttempt>,
    val deletedItems: List<DeletedItem> = emptyList(),
)

@Serializable
data class DeletedItem(
    val id: String,
    val type: String, // "gym", "problem", "session", "attempt"
    val deletedAt: String,
)

// Platform-neutral gym representation for backup/restore
@Serializable
data class BackupGym(
    val id: String,
    val name: String,
    val location: String? = null,
    val supportedClimbTypes: List<ClimbType>,
    val difficultySystems: List<DifficultySystem>,
    @kotlinx.serialization.SerialName("customDifficultyGrades")
    val customDifficultyGrades: List<String>? = null,
    val notes: String? = null,
    val createdAt: String,
    val updatedAt: String,
) {
    companion object {
        fun fromGym(gym: Gym): BackupGym {
            return BackupGym(
                id = gym.id,
                name = gym.name,
                location = gym.location,
                supportedClimbTypes = gym.supportedClimbTypes,
                difficultySystems = gym.difficultySystems,
                customDifficultyGrades = gym.customDifficultyGrades.ifEmpty { null },
                notes = gym.notes,
                createdAt = gym.createdAt,
                updatedAt = gym.updatedAt,
            )
        }
    }

    fun toGym(): Gym {
        return Gym(
            id = id,
            name = name,
            location = location,
            supportedClimbTypes = supportedClimbTypes,
            difficultySystems = difficultySystems,
            customDifficultyGrades = customDifficultyGrades ?: emptyList(),
            notes = notes,
            createdAt = createdAt,
            updatedAt = updatedAt,
        )
    }
}

// Platform-neutral problem representation for backup/restore
@Serializable
data class BackupProblem(
    val id: String,
    val gymId: String,
    val name: String? = null,
    val description: String? = null,
    val climbType: ClimbType,
    val difficulty: DifficultyGrade,
    val tags: List<String>? = null,
    val location: String? = null,
    val imagePaths: List<String>? = null,
    val isActive: Boolean = true,
    val dateSet: String? = null,
    val notes: String? = null,
    val createdAt: String,
    val updatedAt: String,
) {
    companion object {
        fun fromProblem(problem: Problem): BackupProblem {
            return BackupProblem(
                id = problem.id,
                gymId = problem.gymId,
                name = problem.name,
                description = problem.description,
                climbType = problem.climbType,
                difficulty = problem.difficulty,
                tags = problem.tags,
                location = problem.location,
                imagePaths =
                if (problem.imagePaths.isEmpty()) {
                    null
                } else {
                    problem.imagePaths.map { path -> path.substringAfterLast('/') }
                },
                isActive = problem.isActive,
                dateSet = problem.dateSet,
                notes = problem.notes,
                createdAt = problem.createdAt,
                updatedAt = problem.updatedAt,
            )
        }
    }

    fun toProblem(): Problem {
        return Problem(
            id = id,
            gymId = gymId,
            name = name,
            description = description,
            climbType = climbType,
            difficulty = difficulty,
            tags = tags ?: emptyList(),
            location = location,
            imagePaths = imagePaths ?: emptyList(),
            isActive = isActive,
            dateSet = dateSet,
            notes = notes,
            createdAt = createdAt,
            updatedAt = updatedAt,
        )
    }

    fun withUpdatedImagePaths(newImagePaths: List<String>): BackupProblem {
        return copy(imagePaths = newImagePaths.ifEmpty { null })
    }
}

// Platform-neutral climb session representation for backup/restore
@Serializable
data class BackupClimbSession(
    val id: String,
    val gymId: String,
    val date: String,
    val startTime: String? = null,
    val endTime: String? = null,
    val duration: Long? = null,
    val status: SessionStatus,
    val notes: String? = null,
    val createdAt: String,
    val updatedAt: String,
) {
    companion object {
        fun fromClimbSession(session: ClimbSession): BackupClimbSession {
            return BackupClimbSession(
                id = session.id,
                gymId = session.gymId,
                date = session.date,
                startTime = session.startTime,
                endTime = session.endTime,
                duration = session.duration,
                status = session.status,
                notes = session.notes,
                createdAt = session.createdAt,
                updatedAt = session.updatedAt,
            )
        }
    }

    fun toClimbSession(): ClimbSession {
        return ClimbSession(
            id = id,
            gymId = gymId,
            date = date,
            startTime = startTime,
            endTime = endTime,
            duration = duration,
            status = status,
            notes = notes,
            createdAt = createdAt,
            updatedAt = updatedAt,
        )
    }
}

// Platform-neutral attempt representation for backup/restore
@Serializable
data class BackupAttempt(
    val id: String,
    val sessionId: String,
    val problemId: String,
    val result: AttemptResult,
    val highestHold: String? = null,
    val notes: String? = null,
    val duration: Long? = null,
    val restTime: Long? = null,
    val timestamp: String,
    val createdAt: String,
    val updatedAt: String? = null,
) {
    companion object {
        fun fromAttempt(attempt: Attempt): BackupAttempt {
            return BackupAttempt(
                id = attempt.id,
                sessionId = attempt.sessionId,
                problemId = attempt.problemId,
                result = attempt.result,
                highestHold = attempt.highestHold,
                notes = attempt.notes,
                duration = attempt.duration,
                restTime = attempt.restTime,
                timestamp = attempt.timestamp,
                createdAt = attempt.createdAt,
                updatedAt = attempt.updatedAt,
            )
        }
    }

    fun toAttempt(): Attempt {
        return Attempt(
            id = id,
            sessionId = sessionId,
            problemId = problemId,
            result = result,
            highestHold = highestHold,
            notes = notes,
            duration = duration,
            restTime = restTime,
            timestamp = timestamp,
            createdAt = createdAt,
            updatedAt = updatedAt ?: createdAt,
        )
    }
}
