<?php

/**
 * Клас для роботи з cookies
 * Управління cookies з додатковою безпекою
 *
 * @package Flowaxy\Interface\Http
 * @version 1.0.0 Alpha prerelease
 */

declare(strict_types=1);

namespace Flowaxy\Interface\Http;

use Flowaxy\Infrastructure\Security\Encryption;

final class Cookie
{
    /**
     * Встановлення cookie
     *
     * @param string $name Ім'я cookie
     * @param string $value Значення
     * @param int $expire Час закінчення (Unix timestamp, 0 = до закриття браузера)
     * @param string $path Шлях
     * @param string|null $domain Домен
     * @param bool $secure Тільки через HTTPS
     * @param bool $httponly Тільки через HTTP (не доступно через JavaScript)
     * @param string $samesite SameSite атрибут (Strict, Lax, None)
     * @return bool
     */
    public static function set(
        string $name,
        string $value,
        int $expire = 0,
        string $path = '/',
        ?string $domain = null,
        bool $secure = false,
        bool $httponly = true,
        string $samesite = 'Lax'
    ): bool {
        if (headers_sent()) {
            return false;
        }

        $domain = $domain ?? \Flowaxy\Infrastructure\Security\RequestFilter::server('HTTP_HOST', '', 'string');

        // Перевіряємо реальне HTTPS з'єднання
        $realHttps = (
            (!empty(\Flowaxy\Infrastructure\Security\RequestFilter::server('HTTPS', '', 'string')) && \Flowaxy\Infrastructure\Security\RequestFilter::server('HTTPS', '', 'string') !== 'off') ||
            (\Flowaxy\Infrastructure\Security\RequestFilter::server('REQUEST_SCHEME', '', 'string') === 'https') ||
            ((int)\Flowaxy\Infrastructure\Security\RequestFilter::server('SERVER_PORT', 0, 'int') === 443) ||
            (\Flowaxy\Infrastructure\Security\RequestFilter::server('HTTP_X_FORWARDED_PROTO', '', 'string') === 'https')
        );

        // Якщо secure=true, але реальне з'єднання HTTP - вимикаємо secure для сумісності з Edge
        if ($secure && ! $realHttps) {
            $secure = false;
        }

        // Якщо SameSite=None, але secure=false - змінюємо на Lax (Edge вимагає Secure для None)
        if ($samesite === 'None' && ! $secure) {
            $samesite = 'Lax';
        }

        return setcookie($name, $value, [
            'expires' => $expire,
            'path' => $path,
            'domain' => $domain,
            'secure' => $secure,
            'httponly' => $httponly,
            'samesite' => $samesite,
        ]);
    }

    /**
     * Отримання cookie
     *
     * @param string $name Ім'я cookie
     * @param mixed $default Значення за замовчуванням
     * @return mixed
     */
    public static function get(string $name, $default = null)
    {
        return \Flowaxy\Infrastructure\Security\RequestFilter::cookie($name, $default);
    }

    /**
     * Перевірка наявності cookie
     *
     * @param string $name Ім'я cookie
     * @return bool
     */
    public static function has(string $name): bool
    {
        return \Flowaxy\Infrastructure\Security\RequestFilter::cookie($name, null) !== null;
    }

    /**
     * Видалення cookie
     *
     * @param string $name Ім'я cookie
     * @param string $path Шлях
     * @param string|null $domain Домен
     * @return bool
     */
    public static function delete(string $name, string $path = '/', ?string $domain = null): bool
    {
        if (! self::has($name)) {
            return true;
        }

        return self::set($name, '', time() - 3600, $path, $domain);
    }

    /**
     * Встановлення постійної cookie (на рік)
     *
     * @param string $name Ім'я cookie
     * @param string $value Значення
     * @param int $days Кількість днів
     * @return bool
     */
    public static function forever(string $name, string $value, int $days = 365): bool
    {
        return self::set($name, $value, time() + ($days * 86400));
    }

    /**
     * Встановлення зашифрованої cookie
     *
     * @param string $name Ім'я cookie
     * @param string $value Значення
     * @param int $expire Час закінчення
     * @param string|null $key Ключ шифрування
     * @return bool
     */
    public static function encrypted(string $name, string $value, int $expire = 0, ?string $key = null): bool
    {
        try {
            $encrypted = Encryption::quickEncrypt($value, $key);

            return self::set($name, $encrypted, $expire);
        } catch (\Exception $e) {
            Log::Error('Cookie encryption error: ' . $e->getMessage());

            return false;
        }
    }

    /**
     * Отримання розшифрованої cookie
     *
     * @param string $name Ім'я cookie
     * @param mixed $default Значення за замовчуванням
     * @param string|null $key Ключ шифрування
     * @return mixed
     */
    public static function decrypted(string $name, $default = null, ?string $key = null)
    {
        $encrypted = self::get($name);

        if ($encrypted === null) {
            return $default;
        }

        try {
            return Encryption::quickDecrypt($encrypted, $key);
        } catch (\Exception $e) {
            Log::Error('Cookie decryption error: ' . $e->getMessage());

            return $default;
        }
    }
}
