use actix_web::{get, post, web, HttpResponse, Responder, HttpRequest, cookie::{Cookie, SameSite}};
use serde_json::json; 
use crate::models::{RegistrationData, LoginData, LoginResponse};
use crate::error::AppError;
use bcrypt::{hash, verify, DEFAULT_COST};
use sqlx::PgPool;

#[post("/rejestracja")]
pub async fn register(
    form: web::Json<RegistrationData>,
    pool: web::Data<PgPool>,
) -> Result<HttpResponse, AppError> {
    if form.haslo.len() < 8 {
        return Err(AppError::BadRequest("Hasło musi mieć minimum 8 znaków".to_string()));
    }

    if form.haslo != form.confirm_password {
        return Err(AppError::BadRequest("Hasła nie są identyczne".to_string()));
    }

    let hashed_password = hash(&form.haslo, DEFAULT_COST).map_err(|_| AppError::InternalServerError("Błąd serwera".to_string()))?;

    sqlx::query!(
        r#"
        INSERT INTO uzytkownicy (email, haslo, imie)
        VALUES ($1, $2, $3)
        "#,
        form.email,
        hashed_password,
        form.imie
    )
    .execute(pool.get_ref())
    .await
    .map_err(|e| {
        if e.to_string().contains("duplicate key value") {
            AppError::BadRequest("Email jest już zarejestrowany".to_string())
        } else {
            AppError::InternalServerError("Błąd serwera".to_string())
        }
    })?;

    Ok(HttpResponse::Created().body("Konto utworzone pomyślnie"))
}

#[post("/login")]
pub async fn login(
    form: web::Json<LoginData>,
    pool: web::Data<PgPool>,
) -> Result<HttpResponse, AppError> {
    let user = sqlx::query!(
        "SELECT id, haslo, imie FROM uzytkownicy WHERE email = $1",
        form.email
    )
    .fetch_optional(pool.get_ref())
    .await
    .map_err(|_| AppError::InternalServerError("Błąd serwera".to_string()))?
    .ok_or_else(|| AppError::Unauthorized("Nieprawidłowe dane".to_string()))?;

    if verify(&form.haslo, &user.haslo).map_err(|_| AppError::InternalServerError("Błąd serwera".to_string()))? {
        let token = format!("user-{}-token", user.id);
        
        let cookie = Cookie::build("auth_token", &token)
            .path("/")
            .max_age(actix_web::cookie::time::Duration::days(7))
            .http_only(true)
            .same_site(SameSite::Lax)
            .finish();

        let mut response = HttpResponse::Ok()
            .json(LoginResponse {
                token: token.clone(),
                imie: user.imie,
            });
        
        response.add_cookie(&cookie)
            .map_err(|e| {
                log::error!("Błąd ustawiania ciasteczka: {}", e);
                AppError::InternalServerError("Błąd serwera".to_string())
            })?;
        
        Ok(response)
    } else {
        Err(AppError::Unauthorized("Nieprawidłowe hasło".to_string()))
    }
}

#[post("/logout")]
pub async fn logout() -> impl Responder {
    let cookie = Cookie::build("auth_token", "")
        .path("/")
        .max_age(actix_web::cookie::time::Duration::seconds(0))
        .http_only(true)
        .finish();

    let mut response = HttpResponse::Ok().json(json!({"status": "success"}));
    
    if let Err(e) = response.add_cookie(&cookie) {
        log::error!("Błąd usuwania ciasteczka: {}", e);
    }
    
    response
}

pub async fn validate_token(req: &HttpRequest) -> Result<i32, AppError> {
    let cookie = req.cookie("auth_token")
        .ok_or_else(|| AppError::Unauthorized("Unauthorized".to_string()))?;

    let token = cookie.value();

    if token.starts_with("user-") {
        let user_id = token.replace("user-", "").replace("-token", "").parse()
            .map_err(|_| AppError::Unauthorized("Invalid token".to_string()))?;
        Ok(user_id)
    } else {
        Err(AppError::Unauthorized("Unauthorized".to_string()))
    }
}

#[get("/api/check-auth")]
pub async fn check_auth(
    req: HttpRequest,
    pool: web::Data<sqlx::PgPool>,
) -> impl Responder {
    let user_id = validate_token(&req).await;
    
    match user_id {
        Ok(user_id) => {
            match sqlx::query!(
                "SELECT imie FROM uzytkownicy WHERE id = $1",
                user_id
            )
            .fetch_one(pool.get_ref())
            .await {
                Ok(user) => HttpResponse::Ok().json(json!({
                    "authenticated": true,
                    "user": {
                        "id": user_id,
                        "imie": user.imie
                    }
                })),
                Err(_) => HttpResponse::Ok().json(json!({
                    "authenticated": false,
                    "user": null
                }))
            }
        },
        Err(_) => HttpResponse::Ok().json(json!({
            "authenticated": false,
            "user": null
        }))
    }
}
