// Utility to generate bcrypt hashes from tokens
#include <iostream>
#include <string>
#include <cstdlib>
#include <termios.h>
#include <unistd.h>
#include "bcrypt.hpp"

using namespace simple_object_storage;

// Function to read password without echoing to terminal
std::string readPasswordFromStdin() {
    struct termios oldt, newt;
    tcgetattr(STDIN_FILENO, &oldt);
    newt = oldt;
    newt.c_lflag &= ~ECHO;
    tcsetattr(STDIN_FILENO, TCSANOW, &newt);
    
    std::string password;
    std::getline(std::cin, password);
    
    tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
    std::cout << std::endl;
    
    return password;
}

int main(int argc, char* argv[]) {
    std::string token;
    int cost = BCrypt::DEFAULT_COST;
    bool verify_mode = false;
    bool quiet_mode = false;
    
    // Parse command line arguments
    for (int i = 1; i < argc; ++i) {
        std::string arg = argv[i];
        if (arg == "--help" || arg == "-h") {
            std::cout << "Usage: " << argv[0] << " [OPTIONS] [TOKEN]\n"
                     << "\nGenerate bcrypt hashes for authentication tokens.\n"
                     << "\nOptions:\n"
                     << "  -h, --help       Show this help message\n"
                     << "  -c, --cost N     Set bcrypt cost factor (4-31, default: " << BCrypt::DEFAULT_COST << ")\n"
                     << "  -v, --verify     Verify a token against a hash\n"
                     << "  -q, --quiet      Quiet mode (only output hash)\n"
                     << "  -g, --generate   Generate a random token and hash it\n"
                     << "\nExamples:\n"
                     << "  " << argv[0] << " mytoken123          # Hash a token\n"
                     << "  " << argv[0] << " -c 14 mytoken123    # Hash with cost 14\n"
                     << "  " << argv[0] << "                     # Read token from stdin\n"
                     << "  " << argv[0] << " -v                  # Verify token against hash\n"
                     << "  " << argv[0] << " -g                  # Generate random token\n";
            return 0;
        } else if (arg == "--cost" || arg == "-c") {
            if (i + 1 < argc) {
                cost = std::atoi(argv[++i]);
                if (cost < BCrypt::MIN_COST || cost > BCrypt::MAX_COST) {
                    std::cerr << "Error: Cost must be between " << BCrypt::MIN_COST 
                             << " and " << BCrypt::MAX_COST << std::endl;
                    return 1;
                }
            } else {
                std::cerr << "Error: --cost requires an argument\n";
                return 1;
            }
        } else if (arg == "--verify" || arg == "-v") {
            verify_mode = true;
        } else if (arg == "--quiet" || arg == "-q") {
            quiet_mode = true;
        } else if (arg == "--generate" || arg == "-g") {
            // Generate a random token
            const char* charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
            const size_t charset_size = 62;
            const size_t token_length = 32;
            
            std::random_device rd;
            std::mt19937 gen(rd());
            std::uniform_int_distribution<> dis(0, charset_size - 1);
            
            token = "";
            for (size_t i = 0; i < token_length; ++i) {
                token += charset[dis(gen)];
            }
            
            if (!quiet_mode) {
                std::cout << "Generated token: " << token << std::endl;
            }
        } else if (!arg.empty() && arg[0] != '-') {
            token = arg;
        } else {
            std::cerr << "Error: Unknown option: " << arg << "\n";
            return 1;
        }
    }
    
    if (verify_mode) {
        // Verification mode
        if (!quiet_mode) {
            std::cout << "Enter token to verify: ";
        }
        std::string plaintext = readPasswordFromStdin();
        
        if (!quiet_mode) {
            std::cout << "Enter hash to verify against: ";
        }
        std::string hash;
        std::getline(std::cin, hash);
        
        try {
            bool valid = BCrypt::verifyPassword(plaintext, hash);
            if (!quiet_mode) {
                std::cout << "Verification result: ";
            }
            std::cout << (valid ? "VALID" : "INVALID") << std::endl;
            return valid ? 0 : 1;
        } catch (const std::exception& e) {
            std::cerr << "Error: " << e.what() << std::endl;
            return 1;
        }
    } else {
        // Hash generation mode
        if (token.empty()) {
            if (!quiet_mode) {
                std::cout << "Enter token to hash: ";
            }
            token = readPasswordFromStdin();
        }
        
        if (token.empty()) {
            std::cerr << "Error: Token cannot be empty\n";
            return 1;
        }
        
        try {
            std::string hash = BCrypt::hashPassword(token, cost);
            if (!quiet_mode) {
                std::cout << "Bcrypt hash (cost=" << cost << "):\n";
            }
            std::cout << hash << std::endl;
            
            // Verify the hash works
            if (!quiet_mode) {
                bool verified = BCrypt::verifyPassword(token, hash);
                if (!verified) {
                    std::cerr << "Warning: Generated hash failed verification!\n";
                    return 1;
                }
                std::cout << "Hash verified successfully.\n";
            }
        } catch (const std::exception& e) {
            std::cerr << "Error: " << e.what() << std::endl;
            return 1;
        }
    }
    
    return 0;
}