<?php

declare(strict_types=1);

namespace App\Framework\Encryption;

use App\Framework\Random\RandomGenerator;
use RuntimeException;

/**
 * Basic encryption fallback for environments without OpenSSL
 * WARNING: This is NOT cryptographically secure and should only be used for development!
 */
final readonly class BasicEncryption implements EncryptionInterface
{
    private const METHOD = 'BASIC-XOR';
    private const PREFIX = 'BASIC[';
    private const SUFFIX = ']';
    private const MIN_KEY_LENGTH = 16;

    public function __construct(
        private RandomGenerator $randomGenerator,
        private string $encryptionKey
    ) {
        if (! $this->validateKey($this->encryptionKey)) {
            throw new RuntimeException('Encryption key must be at least ' . self::MIN_KEY_LENGTH . ' characters');
        }
    }

    public function encrypt(string $data): string
    {
        // Generate a random salt
        $salt = $this->randomGenerator->bytes(8);
        $saltHex = bin2hex($salt);

        // Create expanded key from base key + salt
        $expandedKey = hash('sha256', $this->encryptionKey . $saltHex, true);

        // Simple XOR encryption (NOT secure, only for fallback!)
        $encrypted = $this->xorEncrypt($data, $expandedKey);

        // Combine salt + encrypted data
        $payload = base64_encode($salt . $encrypted);

        return self::PREFIX . $payload . self::SUFFIX;
    }

    public function decrypt(string $encryptedData): string
    {
        if (! $this->isEncrypted($encryptedData)) {
            throw new RuntimeException('Data does not appear to be encrypted with this method');
        }

        // Remove prefix and suffix
        $payload = substr(
            $encryptedData,
            strlen(self::PREFIX),
            -strlen(self::SUFFIX)
        );

        $data = base64_decode($payload);
        if ($data === false) {
            throw new RuntimeException('Invalid base64 encoding in encrypted data');
        }

        if (strlen($data) < 8) {
            throw new RuntimeException('Encrypted data is too short to contain valid salt');
        }

        // Extract salt and encrypted data
        $salt = substr($data, 0, 8);
        $encrypted = substr($data, 8);
        $saltHex = bin2hex($salt);

        // Recreate expanded key
        $expandedKey = hash('sha256', $this->encryptionKey . $saltHex, true);

        // Decrypt using XOR
        return $this->xorDecrypt($encrypted, $expandedKey);
    }

    public function isEncrypted(string $data): bool
    {
        return str_starts_with($data, self::PREFIX) && str_ends_with($data, self::SUFFIX);
    }

    public function getMethod(): string
    {
        return self::METHOD;
    }

    public function validateKey(string $key): bool
    {
        return strlen($key) >= self::MIN_KEY_LENGTH;
    }

    /**
     * Simple XOR encryption (NOT cryptographically secure!)
     */
    private function xorEncrypt(string $data, string $key): string
    {
        $result = '';
        $keyLen = strlen($key);
        $dataLen = strlen($data);

        for ($i = 0; $i < $dataLen; $i++) {
            $result .= $data[$i] ^ $key[$i % $keyLen];
        }

        return $result;
    }

    /**
     * Simple XOR decryption (same as encryption for XOR)
     */
    private function xorDecrypt(string $encrypted, string $key): string
    {
        return $this->xorEncrypt($encrypted, $key); // XOR is symmetric
    }

    /**
     * Generate a new encryption key suitable for basic encryption
     */
    public function generateKey(): string
    {
        return base64_encode($this->randomGenerator->bytes(self::MIN_KEY_LENGTH));
    }

    /**
     * Get encryption metadata for debugging/logging
     */
    public function getMetadata(): array
    {
        return [
            'method' => self::METHOD,
            'key_length' => self::MIN_KEY_LENGTH,
            'prefix' => self::PREFIX,
            'suffix' => self::SUFFIX,
            'warning' => 'NOT CRYPTOGRAPHICALLY SECURE - DEVELOPMENT ONLY',
        ];
    }
}
