use crate::{model::client::Client, Backend};

pub(crate) struct Rank {
    pub(crate) rank: i64,
    pub(crate) client: Client,
    pub(crate) amount: i64,
    pub(crate) show_dots_above: bool,
}

impl Backend {
    pub(crate) async fn amount_participants(&self) -> i64 {
        match self {
            Backend::Sqlite(db) => {
                let row =
                    sqlx::query!("SELECT COUNT(DISTINCT client_uuid) AS count FROM sightings; ")
                        .fetch_one(db)
                        .await
                        .unwrap();

                row.count
            }
        }
    }

    pub(crate) async fn highscore(&self, client: &Client) -> Vec<Rank> {
        match self {
            Backend::Sqlite(db) => {
                let rows = sqlx::query!(
                    "WITH ranked_clients AS (
                        SELECT 
                            DENSE_RANK() OVER (ORDER BY COUNT(s.client_uuid) DESC) as rank,
                            c.name,
                            c.uuid,
                            COUNT(s.client_uuid) as amount
                        FROM client c
                        LEFT JOIN sightings s ON c.uuid = s.client_uuid
                        GROUP BY c.uuid, c.name
                    )
                    SELECT rank, name, uuid, amount
                    FROM ranked_clients
                    WHERE rank <= COALESCE(
                        (SELECT rank FROM ranked_clients ORDER BY rank LIMIT 1 OFFSET 9),
                        (SELECT MAX(rank) FROM ranked_clients)
                    ) AND amount > 0
                    ORDER BY rank, name"
                )
                .fetch_all(db)
                .await
                .unwrap_or_default();

                let mut ret: Vec<Rank> = rows
                    .into_iter()
                    .map(|row| Rank {
                        rank: row.rank.unwrap(),
                        client: Client {
                            uuid: row.uuid.unwrap(),
                            name: row.name,
                        },
                        amount: row.amount.unwrap(),
                        show_dots_above: false,
                    })
                    .collect();

                let user_is_in_top = ret.iter().any(|x| &x.client == client);
                if !user_is_in_top {
                    let row = sqlx::query!(
                        "WITH ranked_clients AS (
                        SELECT 
                            DENSE_RANK() OVER (ORDER BY COUNT(s.client_uuid) DESC) as rank,
                            c.name,
                            c.uuid,
                            COUNT(s.client_uuid) as amount
                        FROM client c
                        LEFT JOIN sightings s ON c.uuid = s.client_uuid
                        GROUP BY c.uuid, c.name
                    )
                    SELECT rank, name, uuid, amount
                    FROM ranked_clients
                    WHERE uuid = ? 
                    ORDER BY rank, name",
                        client.uuid
                    )
                    .fetch_one(db)
                    .await
                    .unwrap();

                    ret.push(Rank {
                        rank: row.rank,
                        client: Client {
                            uuid: row.uuid,
                            name: row.name,
                        },
                        amount: row.amount,
                        show_dots_above: true,
                    })
                }

                ret
            }
        }
    }
}
