<?php
declare(strict_types=1);

namespace App\Core\Support;

final class Flash
{
    private const FLASH_KEY = '_flash';
    private const QUEUE_KEY = '_flash_queue';
    private const ALLOWED_TYPES = ['info', 'success', 'warning', 'danger'];

    public static function set(string $key, mixed $value): void
    {
        if (!isset($_SESSION[self::FLASH_KEY]) || !is_array($_SESSION[self::FLASH_KEY])) {
            $_SESSION[self::FLASH_KEY] = [];
        }

        $_SESSION[self::FLASH_KEY][$key] = $value;
    }

    public static function get(string $key, mixed $default = null): mixed
    {
        if (
            !isset($_SESSION[self::FLASH_KEY]) ||
            !is_array($_SESSION[self::FLASH_KEY]) ||
            !array_key_exists($key, $_SESSION[self::FLASH_KEY])
        ) {
            return $default;
        }

        $value = $_SESSION[self::FLASH_KEY][$key];
        unset($_SESSION[self::FLASH_KEY][$key]);

        if (empty($_SESSION[self::FLASH_KEY])) {
            unset($_SESSION[self::FLASH_KEY]);
        }

        return $value;
    }

    public static function push(string $type, string $message): void
    {
        $normalizedType = in_array($type, self::ALLOWED_TYPES, true) ? $type : 'info';

        if (!isset($_SESSION[self::QUEUE_KEY]) || !is_array($_SESSION[self::QUEUE_KEY])) {
            $_SESSION[self::QUEUE_KEY] = [];
        }

        $_SESSION[self::QUEUE_KEY][] = [
            'type' => $normalizedType,
            'message' => $message,
        ];
    }

    /**
     * Returns and clears all queued flash entries (typed queue + legacy key/value map).
     *
     * @return list<array{type: string, message: string}>
     */
    public static function all(): array
    {
        $entries = [];

        if (isset($_SESSION[self::QUEUE_KEY]) && is_array($_SESSION[self::QUEUE_KEY])) {
            foreach ($_SESSION[self::QUEUE_KEY] as $entry) {
                if (!is_array($entry)) {
                    continue;
                }
                $type = is_string($entry['type'] ?? null) ? $entry['type'] : 'info';
                $message = is_string($entry['message'] ?? null) ? $entry['message'] : '';
                if ($message === '') {
                    continue;
                }
                if (!in_array($type, self::ALLOWED_TYPES, true)) {
                    $type = 'info';
                }
                $entries[] = ['type' => $type, 'message' => $message];
            }
            unset($_SESSION[self::QUEUE_KEY]);
        }

        if (isset($_SESSION[self::FLASH_KEY]) && is_array($_SESSION[self::FLASH_KEY])) {
            foreach ($_SESSION[self::FLASH_KEY] as $key => $value) {
                if (!is_string($value) || $value === '') {
                    continue;
                }
                $entries[] = [
                    'type' => self::inferTypeFromKey((string) $key),
                    'message' => $value,
                ];
            }
            unset($_SESSION[self::FLASH_KEY]);
        }

        return $entries;
    }

    private static function inferTypeFromKey(string $key): string
    {
        $lower = strtolower($key);

        if (str_contains($lower, 'error') || str_contains($lower, 'fail') || str_contains($lower, 'danger')) {
            return 'danger';
        }
        if (str_contains($lower, 'warning') || str_contains($lower, 'warn')) {
            return 'warning';
        }
        if (
            str_contains($lower, 'success')
            || str_ends_with($lower, '.save')
            || str_contains($lower, 'saved')
            || str_contains($lower, '.created')
            || str_contains($lower, '.deleted')
            || str_contains($lower, '.toggled')
        ) {
            return 'success';
        }

        return 'info';
    }
}
