// SPDX-License-Identifier: Apache-2.0
// Copyright 2025 Caesar Cipher Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "CaesarCipher.h"
#include <iostream>
#include <string>
#include <cctype>

// Constructor
CaesarCipher::CaesarCipher(int shift) : mShift(shift) {
    // Normalize shift to be within 0-25 range
    mShift = ((shift % ALPHABET_SIZE) + ALPHABET_SIZE) % ALPHABET_SIZE;
}

// Destructor
CaesarCipher::~CaesarCipher() {
    // No dynamic memory to clean up
}

// Encrypt a single character
char CaesarCipher::EncryptChar(char character) const {
    if (std::isalpha(character)) {
        char base = std::isupper(character) ? 'A' : 'a';
        return static_cast<char>((character - base + mShift) % ALPHABET_SIZE + base);
    }
    return character; // Return unchanged if not alphabetic
}

// Decrypt a single character
char CaesarCipher::DecryptChar(char character) const {
    if (std::isalpha(character)) {
        char base = std::isupper(character) ? 'A' : 'a';
        return static_cast<char>((character - base - mShift + ALPHABET_SIZE) % ALPHABET_SIZE + base);
    }
    return character; // Return unchanged if not alphabetic
}

// Encrypt a string
std::string CaesarCipher::Encrypt(const std::string& plaintext) const {
    std::string encrypted_text;
    encrypted_text.reserve(plaintext.length()); // Pre-allocate memory for efficiency
    
    for (char character : plaintext) {
        encrypted_text += EncryptChar(character);
    }
    
    return encrypted_text;
}

// Decrypt a string
std::string CaesarCipher::Decrypt(const std::string& ciphertext) const {
    std::string decrypted_text;
    decrypted_text.reserve(ciphertext.length()); // Pre-allocate memory for efficiency
    
    for (char character : ciphertext) {
        decrypted_text += DecryptChar(character);
    }
    
    return decrypted_text;
}

// Get current shift value
int CaesarCipher::GetShift() const {
    return mShift;
}

// Set new shift value
void CaesarCipher::SetShift(int shift) {
    mShift = ((shift % ALPHABET_SIZE) + ALPHABET_SIZE) % ALPHABET_SIZE;
}

// Brute force decrypt - try all possible shifts
std::vector<std::string> CaesarCipher::BruteForceDecrypt(const std::string& ciphertext) {
    std::vector<std::string> all_possibilities;
    all_possibilities.reserve(ALPHABET_SIZE);
    
    for (int shift = 0; shift < ALPHABET_SIZE; ++shift) {
        CaesarCipher temp_cipher(shift);
        all_possibilities.push_back(temp_cipher.Decrypt(ciphertext));
    }
    
    return all_possibilities;
}

// Check if character is valid for Caesar cipher (alphabetic)
bool CaesarCipher::IsValidChar(char character) {
    return std::isalpha(character);
}

// Demonstrate Caesar cipher functionality
void CaesarCipher::Demonstrate() {
    std::cout << "=== Caesar Cipher Demonstration ===" << std::endl;
    
    std::string test_message = "Hello, World! This is a test message.";
    std::cout << "Original message: " << test_message << std::endl;
    
    // Test with different shifts
    for (int shift : {3, 7, 13, 25}) {
        CaesarCipher cipher(shift);
        std::string encrypted = cipher.Encrypt(test_message);
        std::string decrypted = cipher.Decrypt(encrypted);
        
        std::cout << "\nShift " << shift << ":" << std::endl;
        std::cout << "  Encrypted: " << encrypted << std::endl;
        std::cout << "  Decrypted: " << decrypted << std::endl;
        std::cout << "  Match: " << (test_message == decrypted ? "YES" : "NO") << std::endl;
    }
    
    // Demonstrate brute force
    std::cout << "\n=== Brute Force Decryption ===" << std::endl;
    CaesarCipher cipher(7);
    std::string secret_message = "Secret Message";
    std::string encrypted_secret = cipher.Encrypt(secret_message);
    std::cout << "Encrypted secret: " << encrypted_secret << std::endl;
    
    std::vector<std::string> possibilities = BruteForceDecrypt(encrypted_secret);
    std::cout << "All possible decryptions:" << std::endl;
    for (size_t i = 0; i < possibilities.size(); ++i) {
        std::cout << "  Shift " << i << ": " << possibilities[i] << std::endl;
    }
}

// Main function for standalone execution
int main() {
    try {
        // Create cipher with shift of 3 (classic Caesar cipher)
        CaesarCipher cipher(3);
        
        std::string message;
        std::cout << "Enter a message to encrypt: ";
        std::getline(std::cin, message);
        
        if (message.empty()) {
            // If no input provided, run demonstration
            CaesarCipher::Demonstrate();
            return 0;
        }
        
        // Encrypt the message
        std::string encrypted = cipher.Encrypt(message);
        std::cout << "Encrypted message: " << encrypted << std::endl;
        
        // Decrypt the message
        std::string decrypted = cipher.Decrypt(encrypted);
        std::cout << "Decrypted message: " << decrypted << std::endl;
        
        // Verify encryption/decryption worked correctly
        if (message == decrypted) {
            std::cout << "✓ Encryption/Decryption successful!" << std::endl;
        } else {
            std::cout << "✗ Error in encryption/decryption process!" << std::endl;
            return 1;
        }
        
        // Ask if user wants to see brute force attack
        std::cout << "\nWould you like to see all possible decryptions? (y/n): ";
        char choice;
        std::cin >> choice;
        
        if (choice == 'y' || choice == 'Y') {
            std::vector<std::string> all_decryptions = CaesarCipher::BruteForceDecrypt(encrypted);
            std::cout << "\nAll possible decryptions:" << std::endl;
            for (size_t i = 0; i < all_decryptions.size(); ++i) {
                std::cout << "Shift " << i << ": " << all_decryptions[i] << std::endl;
            }
        }
        
    } catch (const std::exception& e) {
        std::cerr << "Error: " << e.what() << std::endl;
        return 1;
    }
    
    return 0;
}