use actix_web::{get, post, delete, web, HttpResponse, HttpRequest, Responder};
use crate::models::{CartItem, CartItemResponse, CheckoutRequest};
use crate::error::AppError;
use sqlx::PgPool;
use crate::auth::validate_token;
use bigdecimal::BigDecimal;
use serde_json::json;
use log;
use std::str::FromStr;
use crate::models::CartQuantityUpdate;

#[get("/api/cart")]
pub async fn get_cart(
    req: HttpRequest,
    pool: web::Data<PgPool>,
) -> Result<HttpResponse, AppError> {
    let user_id = validate_token(&req).await?;

    let cart_items = sqlx::query_as!(
        CartItemResponse,
        r#"
        SELECT
            k.book_id as "book_id!",
            k.quantity as "quantity!",
            b.tytul as "tytul!",
            b.cena as "cena!",
            COALESCE('/images/' || NULLIF(b.obraz_url, ''), '/images/placeholder.jpg') as "obraz_url!"
        FROM koszyk k
        JOIN ksiazki b ON k.book_id = b.id
        WHERE k.user_id = $1
        ORDER BY b.tytul"#,
        user_id
    )
    .fetch_all(pool.get_ref())
    .await
    .map_err(|e| {
        log::error!("Błąd bazy danych: {}", e);
        AppError::InternalServerError("Błąd serwera".to_string())
    })?;

    Ok(HttpResponse::Ok().json(cart_items))
}

#[post("/api/add-to-cart")]
pub async fn add_to_cart(
    cart_item: web::Json<CartItem>,
    req: HttpRequest,
    pool: web::Data<PgPool>,
) -> Result<HttpResponse, AppError> {
    let user_id = validate_token(&req).await?;

    sqlx::query!(
        "INSERT INTO koszyk (user_id, book_id, quantity)
        VALUES ($1, $2, $3)
        ON CONFLICT (user_id, book_id)
        DO UPDATE SET quantity = koszyk.quantity + $3",
        user_id,
        cart_item.book_id,
        cart_item.quantity
    )
    .execute(pool.get_ref())
    .await
    .map_err(|e| {
        log::error!("Błąd bazy danych: {}", e);
        AppError::InternalServerError("Błąd serwera".to_string())
    })?;

    Ok(HttpResponse::Ok().json(json!({"status": "success"})))
}

#[delete("/api/remove-from-cart/{book_id}")]
pub async fn remove_from_cart(
    req: HttpRequest,
    pool: web::Data<PgPool>,
    book_id: web::Path<i32>,
) -> Result<HttpResponse, AppError> {
    let user_id = validate_token(&req).await?;
    let book_id = book_id.into_inner();

    sqlx::query!(
        "DELETE FROM koszyk WHERE user_id = $1 AND book_id = $2",
        user_id,
        book_id
    )
    .execute(pool.get_ref())
    .await
    .map_err(|e| {
        log::error!("Błąd bazy danych: {}", e);
        AppError::InternalServerError("Błąd serwera".to_string())
    })?;

    Ok(HttpResponse::Ok().json(json!({"status": "success"})))
}

#[post("/api/checkout")]
pub async fn checkout(
    req: HttpRequest,
    pool: web::Data<PgPool>,
    data: web::Json<CheckoutRequest>,
) -> Result<HttpResponse, AppError> {
    let user_id = validate_token(&req).await?;

    let mut transaction = pool.begin().await
        .map_err(|e| {
            log::error!("Błąd rozpoczynania transakcji: {}", e);
            AppError::InternalServerError("Błąd serwera".to_string())
        })?;

    let total_str = format!("{:.2}", data.total);
    let total_bigdecimal = BigDecimal::from_str(&total_str)
        .map_err(|_| AppError::BadRequest("Invalid total value".to_string()))?;

    let order_record = sqlx::query!(
        "INSERT INTO zamowienia (user_id, suma_totalna, typ_dostawy)
        VALUES ($1, $2, $3) RETURNING id",
        user_id,
        total_bigdecimal,
        data.delivery_type
    )
    .fetch_one(&mut *transaction)
    .await
    .map_err(|e| {
        log::error!("Błąd tworzenia zamówienia: {}", e);
        AppError::InternalServerError("Błąd serwera".to_string())
    })?;

    let order_id = order_record.id;

    for item in &data.items {
        let book = sqlx::query!(
            "SELECT cena FROM ksiazki WHERE id = $1",
            item.book_id
        )
        .fetch_one(&mut *transaction)
        .await
        .map_err(|e| {
            log::error!("Błąd wyszukiwania książki: {}", e);
            AppError::InternalServerError("Błąd serwera".to_string())
        })?;

        sqlx::query!(
            "INSERT INTO pozycje_zamowienia (zamowienie_id, book_id, ilosc, cena)
            VALUES ($1, $2, $3, $4)",
            order_id,
            item.book_id,
            item.quantity,
            book.cena
        )
        .execute(&mut *transaction)
        .await
        .map_err(|e| {
            log::error!("Błąd dodawania pozycji zamówienia: {}", e);
            AppError::InternalServerError("Błąd serwera".to_string())
        })?;
    }

    sqlx::query!(
        "DELETE FROM koszyk WHERE user_id = $1",
        user_id
    )
    .execute(&mut *transaction)
    .await
    .map_err(|e| {
        log::error!("Błąd czyszczenia koszyka: {}", e);
        AppError::InternalServerError("Błąd serwera".to_string())
    })?;

    transaction.commit().await.map_err(|e| {
        log::error!("Błąd zatwierdzania transakcji: {}", e);
        AppError::InternalServerError("Błąd serwera".to_string())
    })?;
    
    Ok(HttpResponse::Ok().json(json!({"status": "success"})))
}

#[post("/api/update-cart-quantity")]
pub async fn update_cart_quantity(
    req: HttpRequest,
    pool: web::Data<PgPool>,
    data: web::Json<CartQuantityUpdate>,
) -> Result<HttpResponse, AppError> {
    let user_id = validate_token(&req).await?;

    sqlx::query!(
        "UPDATE koszyk SET quantity = quantity + $1 
        WHERE user_id = $2 AND book_id = $3",
        data.change,
        user_id,
        data.book_id
    )
    .execute(pool.get_ref())
    .await
    .map_err(|e| {
        log::error!("Błąd bazy danych: {}", e);
        AppError::InternalServerError("Błąd serwera".to_string())
    })?;

    Ok(HttpResponse::Ok().json(json!({"status": "success"})))
}
