#include "authenticator.h"
#include <iostream>

namespace scar {

Authenticator::Authenticator(std::shared_ptr<Database> db, const std::string& jwt_secret)
    : db_(db), jwt_secret_(jwt_secret) {}

std::string Authenticator::authenticate(const std::string& username, const std::string& password) {
    std::cout << "Authentication attempt for user: '" << username << "'" << std::endl;
    
    // Get user from database
    auto user = db_->getUserByUsername(username);
    if (!user) {
        std::cerr << "Authentication failed: user not found" << std::endl;
        return "";
    }
    
    std::cout << "User found in database, username: '" << user->username << "'" << std::endl;
    std::cout << "Stored salt (first 20 chars): " << user->salt.substr(0, 20) << std::endl;
    std::cout << "Stored hash (first 20 chars): " << user->password_hash.substr(0, 20) << std::endl;
    
    // Hash the provided password with the stored salt
    std::string password_hash = Argon2Wrapper::hashPassword(password, user->salt);
    
    std::cout << "Computed hash (first 20 chars): " << password_hash.substr(0, 20) << std::endl;
    
    // Verify against stored hash
    if (password_hash != user->password_hash) {
        std::cerr << "Authentication failed: incorrect password" << std::endl;
        std::cerr << "  Expected: " << user->password_hash << std::endl;
        std::cerr << "  Got:      " << password_hash << std::endl;
        return "";
    }
    
    // Generate JWT token
    std::string token = JWT::generate(username, jwt_secret_);
    
    // Store token in database
    if (!db_->updateUserToken(username, token)) {
        std::cerr << "Failed to update user token" << std::endl;
        return "";
    }
    
    // Update user status and last login
    db_->updateUserStatus(username, UserStatus::ONLINE);
    db_->updateLastLogin(username);
    
    std::cout << "User '" << username << "' authenticated successfully" << std::endl;
    return token;
}

std::string Authenticator::verifyToken(const std::string& token) {
    // Verify JWT signature and expiration
    if (!JWT::verify(token, jwt_secret_)) {
        return "";
    }
    
    // Extract username
    std::string username = JWT::extractUsername(token);
    if (username.empty()) {
        return "";
    }
    
    // Verify token matches database
    std::string db_username = db_->getUsernameByToken(token);
    if (db_username != username) {
        return "";
    }
    
    return username;
}

bool Authenticator::createUser(const std::string& username, const std::string& password) {
    // Generate salt
    std::string salt = Argon2Wrapper::generateSalt();
    
    // Hash password with salt
    std::string password_hash = Argon2Wrapper::hashPassword(password, salt);
    
    // Create user in database
    bool success = db_->createUser(username, password_hash, salt);
    
    if (success) {
        std::cout << "User '" << username << "' created successfully" << std::endl;
    } else {
        std::cerr << "Failed to create user '" << username << "'" << std::endl;
    }
    
    return success;
}

} // namespace scar
