use backend::rocket_builder;
use backend::repo::mock::{MockUserRepo, MockTokenRepo};
use backend::repo::message_repo::MessageRepository;
use backend::svc::chat_svc::ChatService;
use backend::repo::user_repo::UserRepository;
use backend::repo::{Repo, AccessTokenRepoTrait};
use rocket::local::asynchronous::Client;
use rocket::http::{Status, ContentType, Header};
use serde_json::json;
use std::sync::{Arc, Mutex};
use sqlx::PgPool;
use chrono::Utc;
use backend::svc::llm_service::LlmService;

async fn setup_client() -> (Client, Arc<MockUserRepo>, String) {
    let users = Arc::new(MockUserRepo { users: Mutex::new(vec![]) });
    let tokens = Arc::new(MockTokenRepo { tokens: Mutex::new(vec![]) });
    let pool = PgPool::connect_lazy("postgres://localhost/unused").unwrap();
    let messages = MessageRepository::new(pool.clone());
    let user_repo = Arc::new(UserRepository::new(pool));
    let llm_service = LlmService::new();
    let chat_service = ChatService::new(32, messages, user_repo, llm_service);
    
    let client = Client::tracked(rocket_builder(users.clone(), tokens.clone(), chat_service)).await.expect("valid rocket instance");

    // Create a user and get JWT
    let token_code = "valid-token";
    tokens.create_new(1, "test", token_code, 1, Utc::now(), Utc::now()).await.unwrap();

    client.post("/api/signup")
        .header(ContentType::JSON)
        .body(json!({
            "email": "test@example.com",
            "username": "testuser",
            "password": "password123",
            "access_token": token_code
        }).to_string())
        .dispatch()
        .await;

    let login_res = client.post("/api/login")
        .header(ContentType::JSON)
        .body(json!({
            "username": "testuser",
            "password": "password123"
        }).to_string())
        .dispatch()
        .await;
    
    let auth_resp: serde_json::Value = serde_json::from_str(&login_res.into_string().await.unwrap()).unwrap();
    let jwt = auth_resp["token"].as_str().unwrap().to_string();

    (client, users, jwt)
}

#[rocket::async_test]
async fn test_change_display_name() {
    let (client, users, jwt) = setup_client().await;

    let response = client.patch("/api/settings/display_name")
        .header(ContentType::JSON)
        .header(Header::new("Authorization", format!("Bearer {}", jwt)))
        .body(json!({
            "display_name": "New Display Name"
        }).to_string())
        .dispatch()
        .await;

    assert_eq!(response.status(), Status::Ok);
    
    let user = users.users.lock().unwrap()[0].clone();
    assert_eq!(user.nickname, Some("New Display Name".to_string()));
}

#[rocket::async_test]
async fn test_change_username() {
    let (client, users, jwt) = setup_client().await;

    let response = client.patch("/api/settings/username")
        .header(ContentType::JSON)
        .header(Header::new("Authorization", format!("Bearer {}", jwt)))
        .body(json!({
            "username": "newusername"
        }).to_string())
        .dispatch()
        .await;

    assert_eq!(response.status(), Status::Ok);
    
    let user = users.users.lock().unwrap()[0].clone();
    assert_eq!(user.username, "newusername");
}

#[rocket::async_test]
async fn test_change_password() {
    let (client, _, jwt) = setup_client().await;

    let response = client.post("/api/settings/password")
        .header(ContentType::JSON)
        .header(Header::new("Authorization", format!("Bearer {}", jwt)))
        .body(json!({
            "old_password": "password123",
            "new_password": "newpassword456"
        }).to_string())
        .dispatch()
        .await;

    assert_eq!(response.status(), Status::Ok);

    // Verify login with new password
    let login_res = client.post("/api/login")
        .header(ContentType::JSON)
        .body(json!({
            "username": "testuser",
            "password": "newpassword456"
        }).to_string())
        .dispatch()
        .await;
    
    assert_eq!(login_res.status(), Status::Ok);
}
