use std::path::Path;

use lanspread_db::db::{Availability, Game};
use serde::{Deserialize, Serialize};
use sqlx::sqlite::{SqliteConnectOptions, SqlitePoolOptions};

#[derive(Clone, Debug, Serialize, Deserialize, sqlx::FromRow)]
pub struct EtiGame {
    pub game_id: String,
    pub game_title: String,
    pub game_key: String,
    pub game_release: String,
    pub game_publisher: String,
    pub game_size: f64,
    pub game_readme_de: String,
    pub game_readme_en: String,
    pub game_readme_fr: String,
    pub game_maxplayers: u32,
    pub game_master_req: i32,
    pub genre_de: String,
    pub game_version: String,
}

/// # Errors
pub async fn get_games(db: &Path) -> eyre::Result<Vec<EtiGame>> {
    let options = SqliteConnectOptions::new().filename(db).read_only(true);
    let pool = SqlitePoolOptions::new().connect_with(options).await?;

    let mut games = sqlx::query_as::<_, EtiGame>(
        "SELECT
            g.game_id, g.game_title, g.game_key, g.game_release,
            g.game_publisher, CAST(g.game_size AS REAL) as game_size, g.game_readme_de,
            g.game_readme_en, g.game_readme_fr, CAST(g.game_maxplayers AS INTEGER) as game_maxplayers,
            g.game_master_req, ge.genre_de, g.game_version
         FROM games g
         JOIN genre ge ON g.genre_id = ge.genre_id",
    )
    .fetch_all(&pool)
    .await?;

    games.sort_by(|a, b| a.game_title.cmp(&b.game_title));

    tracing::info!("Found {} games in game.db", games.len());
    for game in &games {
        tracing::debug!("{}: {}", game.game_id, game.game_title);
    }

    Ok(games)
}

impl From<EtiGame> for Game {
    fn from(eti_game: EtiGame) -> Self {
        Self {
            id: eti_game.game_id,
            name: eti_game.game_title,
            description: eti_game.game_readme_de,
            release_year: eti_game.game_release,
            publisher: eti_game.game_publisher,
            max_players: eti_game.game_maxplayers,
            version: eti_game.game_version,
            genre: eti_game.genre_de,
            #[allow(clippy::cast_sign_loss, clippy::cast_possible_truncation)]
            size: (eti_game.game_size * 1024.0 * 1024.0 * 1024.0) as u64,
            downloaded: false,
            installed: false,
            availability: Availability::LocalOnly,
            eti_game_version: None,
            local_version: None,
            peer_count: 0, // ETI games start with 0 peers until peer system discovers them
        }
    }
}
