// SPDX-License-Identifier: Apache-2.0
// Copyright 2025 Simple Encryption 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 "SimpleEncryption.h"
#include <iostream>
#include <random>
#include <algorithm>

// Lifecycle
SimpleEncryption::SimpleEncryption() : mDefaultKey(3) {
    // Default constructor with Caesar shift of 3
}

SimpleEncryption::SimpleEncryption(int key) : mDefaultKey(key) {
    // Constructor with custom default key
}

SimpleEncryption::~SimpleEncryption() {
    // Destructor - nothing to clean up for this simple implementation
}

// Operations
std::string SimpleEncryption::EncryptCaesar(const std::string& plaintext, int shift) {
    if (shift == 0) {
        shift = mDefaultKey;
    }
    
    std::string encrypted_text = "";
    
    for (char character : plaintext) {
        if (IsAlphabetic(character)) {
            encrypted_text += ShiftCharacter(character, shift);
        } else {
            encrypted_text += character; // Keep non-alphabetic characters unchanged
        }
    }
    
    return encrypted_text;
}

std::string SimpleEncryption::DecryptCaesar(const std::string& ciphertext, int shift) {
    if (shift == 0) {
        shift = mDefaultKey;
    }
    
    // Decrypt by shifting in the opposite direction
    return EncryptCaesar(ciphertext, -shift);
}

std::string SimpleEncryption::EncryptXor(const std::string& plaintext, const std::string& key) {
    if (key.empty()) {
        std::cerr << "Error: XOR key cannot be empty" << std::endl;
        return "";
    }
    
    std::string encrypted_text = "";
    size_t key_index = 0;
    
    for (char character : plaintext) {
        encrypted_text += character ^ key[key_index % key.length()];
        key_index++;
    }
    
    return encrypted_text;
}

std::string SimpleEncryption::DecryptXor(const std::string& ciphertext, const std::string& key) {
    // XOR decryption is the same as encryption
    return EncryptXor(ciphertext, key);
}

// Accessors
void SimpleEncryption::SetDefaultKey(int key) {
    mDefaultKey = key;
}

int SimpleEncryption::GetDefaultKey() const {
    return mDefaultKey;
}

// Utilities
bool SimpleEncryption::IsValidText(const std::string& text) const {
    return !text.empty();
}

std::string SimpleEncryption::GenerateRandomKey(int length) const {
    if (length <= 0) {
        return "";
    }
    
    std::string key = "";
    std::random_device random_device;
    std::mt19937 generator(random_device());
    std::uniform_int_distribution<> distribution(33, 126); // Printable ASCII characters
    
    for (int i = 0; i < length; i++) {
        key += static_cast<char>(distribution(generator));
    }
    
    return key;
}

// Helper methods
char SimpleEncryption::ShiftCharacter(char character, int shift) const {
    if (character >= 'A' && character <= 'Z') {
        // Handle uppercase letters
        return static_cast<char>((character - 'A' + shift + 26) % 26 + 'A');
    } else if (character >= 'a' && character <= 'z') {
        // Handle lowercase letters
        return static_cast<char>((character - 'a' + shift + 26) % 26 + 'a');
    }
    
    return character; // Return unchanged if not alphabetic
}

bool SimpleEncryption::IsAlphabetic(char character) const {
    return (character >= 'A' && character <= 'Z') || (character >= 'a' && character <= 'z');
}

char SimpleEncryption::ToUpperCase(char character) const {
    if (character >= 'a' && character <= 'z') {
        return character - 'a' + 'A';
    }
    return character;
}

char SimpleEncryption::ToLowerCase(char character) const {
    if (character >= 'A' && character <= 'Z') {
        return character - 'A' + 'a';
    }
    return character;
}