// SPDX-License-Identifier: Apache-2.0
// Copyright 2025 XOR 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.

package main

import (
	"crypto/rand"
	"crypto/sha256"
	"encoding/base64"
	"errors"
	"fmt"
	"io"
)

// XOREncryption provides XOR encryption and decryption functionality
// Note: XOR encryption is not cryptographically secure and should only be used
// for educational purposes or simple obfuscation
type XOREncryption struct {
	key []byte
}

// NewXOREncryption creates a new XOR encryption instance with a key derived from password
// The password is hashed using SHA-256 to create a consistent key
func NewXOREncryption(password string) *XOREncryption {
	hash := sha256.Sum256([]byte(password))
	return &XOREncryption{
		key: hash[:],
	}
}

// NewXOREncryptionWithKey creates a new XOR encryption instance with a provided key
// The key can be any length, but longer keys provide better security
func NewXOREncryptionWithKey(key []byte) (*XOREncryption, error) {
	if len(key) == 0 {
		return nil, errors.New("key cannot be empty")
	}

	// Create a copy to prevent external modification
	keyCopy := make([]byte, len(key))
	copy(keyCopy, key)

	return &XOREncryption{
		key: keyCopy,
	}, nil
}

// Encrypt encrypts plaintext using XOR cipher
// Returns base64-encoded ciphertext
func (x *XOREncryption) Encrypt(plaintext string) (string, error) {
	if plaintext == "" {
		return "", errors.New("plaintext cannot be empty")
	}

	data := []byte(plaintext)
	encrypted := x.xorBytes(data)

	// Return base64 encoded result
	return base64.StdEncoding.EncodeToString(encrypted), nil
}

// Decrypt decrypts base64-encoded ciphertext using XOR cipher
// XOR encryption is symmetric, so decryption uses the same operation as encryption
func (x *XOREncryption) Decrypt(encodedCiphertext string) (string, error) {
	if encodedCiphertext == "" {
		return "", errors.New("ciphertext cannot be empty")
	}

	// Decode base64
	ciphertext, err := base64.StdEncoding.DecodeString(encodedCiphertext)
	if err != nil {
		return nil, fmt.Errorf("failed to decode base64: %w", err)
	}

	// XOR is symmetric - same operation for encryption and decryption
	decrypted := x.xorBytes(ciphertext)

	return string(decrypted), nil
}

// EncryptBytes encrypts byte data using XOR cipher
// Returns encrypted bytes
func (x *XOREncryption) EncryptBytes(data []byte) ([]byte, error) {
	if len(data) == 0 {
		return nil, errors.New("data cannot be empty")
	}

	encrypted := x.xorBytes(data)
	return encrypted, nil
}

// DecryptBytes decrypts byte data using XOR cipher
// XOR encryption is symmetric, so decryption uses the same operation as encryption
func (x *XOREncryption) DecryptBytes(ciphertext []byte) ([]byte, error) {
	if len(ciphertext) == 0 {
		return nil, errors.New("ciphertext cannot be empty")
	}

	// XOR is symmetric - same operation for encryption and decryption
	decrypted := x.xorBytes(ciphertext)
	return decrypted, nil
}

// xorBytes performs XOR operation on data with the key
// The key is repeated cyclically if data is longer than key
func (x *XOREncryption) xorBytes(data []byte) []byte {
	result := make([]byte, len(data))
	keyLen := len(x.key)

	for i, b := range data {
		result[i] = b ^ x.key[i%keyLen]
	}

	return result
}

// GenerateKey generates a cryptographically secure random key of specified length
func GenerateKey(keySize int) ([]byte, error) {
	if keySize <= 0 {
		return nil, errors.New("key size must be greater than 0")
	}

	key := make([]byte, keySize)
	if _, err := io.ReadFull(rand.Reader, key); err != nil {
		return nil, fmt.Errorf("failed to generate key: %w", err)
	}

	return key, nil
}

// Example usage and demonstration
func main() {
	// Example 1: Using password-based encryption
	fmt.Println("=== XOR Encryption Demo ===")
	fmt.Println("WARNING: XOR encryption is NOT cryptographically secure!")
	fmt.Println("Use only for educational purposes or simple obfuscation.")
	fmt.Println()

	password := "my-secret-password-123"
	xorEnc := NewXOREncryption(password)

	plaintext := "Hello, World! This is a secret message."
	fmt.Printf("Original text: %s\n", plaintext)

	// Encrypt
	encrypted, err := xorEnc.Encrypt(plaintext)
	if err != nil {
		fmt.Printf("Encryption error: %v\n", err)
		return
	}
	fmt.Printf("Encrypted (base64): %s\n", encrypted)

	// Decrypt
	decrypted, err := xorEnc.Decrypt(encrypted)
	if err != nil {
		fmt.Printf("Decryption error: %v\n", err)
		return
	}
	fmt.Printf("Decrypted text: %s\n", decrypted)

	// Verify
	if plaintext == decrypted {
		fmt.Println("✓ Encryption/Decryption successful!")
	} else {
		fmt.Println("✗ Encryption/Decryption failed!")
	}

	fmt.Println()

	// Example 2: Using generated key
	fmt.Println("=== Key-based XOR Encryption Demo ===")

	// Generate a 32-byte key
	key, err := GenerateKey(32)
	if err != nil {
		fmt.Printf("Key generation error: %v\n", err)
		return
	}

	keyBasedEnc, err := NewXOREncryptionWithKey(key)
	if err != nil {
		fmt.Printf("XOR initialization error: %v\n", err)
		return
	}

	data := []byte("Sensitive binary data that needs obfuscation")
	fmt.Printf("Original data: %s\n", string(data))

	// Encrypt bytes
	encryptedBytes, err := keyBasedEnc.EncryptBytes(data)
	if err != nil {
		fmt.Printf("Byte encryption error: %v\n", err)
		return
	}
	fmt.Printf("Encrypted bytes (base64): %s\n", base64.StdEncoding.EncodeToString(encryptedBytes))

	// Decrypt bytes
	decryptedBytes, err := keyBasedEnc.DecryptBytes(encryptedBytes)
	if err != nil {
		fmt.Printf("Byte decryption error: %v\n", err)
		return
	}
	fmt.Printf("Decrypted data: %s\n", string(decryptedBytes))

	// Verify
	if string(data) == string(decryptedBytes) {
		fmt.Println("✓ Byte encryption/decryption successful!")
	} else {
		fmt.Println("✗ Byte encryption/decryption failed!")
	}

	fmt.Println()

	// Example 3: Demonstrating XOR properties
	fmt.Println("=== XOR Cipher Properties Demo ===")

	// Show that XOR is symmetric
	testData := "XOR is symmetric!"
	fmt.Printf("Test data: %s\n", testData)

	encrypted1, _ := xorEnc.Encrypt(testData)
	fmt.Printf("Encrypted once: %s\n", encrypted1)

	// Decrypt (which is the same as encrypt again)
	decrypted1, _ := xorEnc.Decrypt(encrypted1)
	fmt.Printf("Decrypted (encrypted twice): %s\n", decrypted1)

	// Show key repetition
	fmt.Println()
	fmt.Printf("Key length: %d bytes\n", len(xorEnc.key))
	fmt.Printf("Key (first 16 bytes, hex): %x\n", xorEnc.key[:16])

	fmt.Println()
	fmt.Println("=== Security Notes ===")
	fmt.Println("• XOR cipher is NOT cryptographically secure")
	fmt.Println("• Vulnerable to frequency analysis")
	fmt.Println("• Key reuse reveals patterns")
	fmt.Println("• Suitable only for simple obfuscation")
	fmt.Println("• For real security, use AES or other proven algorithms")
	fmt.Println("• Educational and demonstration purposes only")
}