use crate::cents::Cents;

#[derive(Debug, PartialEq, Clone, sqlx::FromRow)]
pub struct LineItem {
    pub id: i64,
    pub order_id: i64,
    pub sku: String,
    pub url: String,
    pub name: String,
    pub quantity: i32,
    pub price: Cents,
    pub taxrate: i32,
    pub total: Cents,
}

pub async fn fetch<'e>(
    id: i64,
    conn: impl sqlx::Executor<'_, Database = sqlx::Postgres>,
) -> Result<Option<LineItem>, sqlx::Error> {
    sqlx::query_as("SELECT * FROM line_items WHERE id = $1")
        .bind(id)
        .fetch_optional(conn)
        .await
}

pub async fn by_order_id<'e>(
    order_id: i64,
    conn: impl sqlx::Executor<'_, Database = sqlx::Postgres>,
) -> Result<Vec<LineItem>, sqlx::Error> {
    sqlx::query_as("SELECT * FROM line_items WHERE order_id = $1 ORDER BY id")
        .bind(order_id)
        .fetch_all(conn)
        .await
}

#[derive(Debug)]
pub struct NewLineItem<'a> {
    pub order_id: i64,
    pub sku: &'a str,
    pub url: &'a str,
    pub name: &'a str,
    pub quantity: i32,
    pub price: Cents,
    pub taxrate: i32,
    pub total: Cents,
}

pub async fn insert<'e>(
    line_item: &NewLineItem<'_>,
    conn: impl sqlx::Executor<'_, Database = sqlx::Postgres>,
) -> Result<LineItem, sqlx::Error> {
    // deconstruct to not miss new properties in the future
    let NewLineItem {
        order_id,
        sku,
        url,
        name,
        quantity,
        price,
        taxrate,
        total,
    } = line_item;

    sqlx::query_as(
        "
            INSERT INTO line_items (
                order_id,
                sku,
                url,
                name,
                quantity,
                price,
                taxrate,
                total
            ) VALUES (
                $1, $2, $3, $4, $5, $6, $7, $8
            )
            RETURNING *
        ",
    )
    .bind(order_id)
    .bind(sku)
    .bind(url)
    .bind(name)
    .bind(quantity)
    .bind(price)
    .bind(taxrate)
    .bind(total)
    .fetch_one(conn)
    .await
}
