<?php

declare(strict_types=1);

function myronFlashSessionKey(): string
{
    return 'myron_flash_messages';
}

function myronNormalizeFlashTone(string $tone): string
{
    return match (strtolower(trim($tone))) {
        'error', 'danger' => 'danger',
        'warn', 'warning' => 'warning',
        'success' => 'success',
        default => 'info',
    };
}

function myronFlashDefaultTitle(string $tone): string
{
    return match ($tone) {
        'success' => 'Success',
        'warning' => 'Warning',
        'danger' => 'Error',
        default => 'Notice',
    };
}

function myronFlashDefaultAutoDismissMs(string $tone): int
{
    return in_array($tone, ['success', 'info'], true) ? 4000 : 0;
}

function myronFlashIconName(string $tone): string
{
    return match ($tone) {
        'success' => 'check-circle',
        'warning' => 'exclamation-triangle',
        'danger' => 'x-circle',
        default => 'info-circle',
    };
}

/**
 * @param array<string, mixed> $options
 * @return array<string, int|string|bool>
 */
function myronCreateFlashMessage(string $message, string $tone = 'info', array $options = []): array
{
    $normalizedMessage = trim($message);
    if ($normalizedMessage === '') {
        throw new InvalidArgumentException('Flash message text is required.');
    }

    $normalizedTone = myronNormalizeFlashTone($tone);
    $title = trim((string) ($options['title'] ?? myronFlashDefaultTitle($normalizedTone)));
    $autoDismissMs = array_key_exists('autoDismissMs', $options)
        ? max(0, (int) $options['autoDismissMs'])
        : myronFlashDefaultAutoDismissMs($normalizedTone);
    $dismissible = array_key_exists('dismissible', $options) ? (bool) $options['dismissible'] : true;
    $role = in_array($normalizedTone, ['warning', 'danger'], true) ? 'alert' : 'status';
    $live = $role === 'alert' ? 'assertive' : 'polite';

    return [
        'id' => (string) ($options['id'] ?? myronGenerateId('flash')),
        'tone' => $normalizedTone,
        'title' => $title,
        'message' => $normalizedMessage,
        'dismissible' => $dismissible,
        'autoDismissMs' => $autoDismissMs,
        'role' => $role,
        'live' => $live,
    ];
}

/**
 * @param array<string, mixed> $options
 */
function myronQueueFlash(string $message, string $tone = 'info', array $options = []): void
{
    myronEnsureSession();

    $queued = myronCreateFlashMessage($message, $tone, $options);
    $existing = $_SESSION[myronFlashSessionKey()] ?? [];
    if (!is_array($existing)) {
        $existing = [];
    }

    $existing[] = $queued;
    $_SESSION[myronFlashSessionKey()] = $existing;
}

/**
 * @param array<string, mixed> $options
 */
function myronRedirectWithFlash(string $location, string $message, string $tone = 'info', array $options = []): never
{
    myronQueueFlash($message, $tone, $options);
    myronRedirect($location);
}

/**
 * @return list<array<string, int|string|bool>>
 */
function myronConsumeFlashMessages(): array
{
    myronEnsureSession();

    $stored = $_SESSION[myronFlashSessionKey()] ?? [];
    unset($_SESSION[myronFlashSessionKey()]);

    if (!is_array($stored)) {
        return [];
    }

    $messages = [];
    foreach ($stored as $entry) {
        if (!is_array($entry)) {
            continue;
        }

        $message = trim((string) ($entry['message'] ?? ''));
        if ($message === '') {
            continue;
        }

        $messages[] = myronCreateFlashMessage(
            $message,
            (string) ($entry['tone'] ?? 'info'),
            [
                'id' => (string) ($entry['id'] ?? myronGenerateId('flash')),
                'dismissible' => (bool) ($entry['dismissible'] ?? true),
                'autoDismissMs' => (int) ($entry['autoDismissMs'] ?? myronFlashDefaultAutoDismissMs((string) ($entry['tone'] ?? 'info'))),
                ...(trim((string) ($entry['title'] ?? '')) !== '' ? ['title' => (string) $entry['title']] : []),
            ]
        );
    }

    return $messages;
}

/**
 * @param list<array<string, int|string|bool>>|null $messages
 * @param array<string, mixed> $options
 */
function myronRenderFlashToastRegion(?array $messages = null, array $options = []): void
{
    $renderMessages = $messages ?? myronConsumeFlashMessages();
    if ($renderMessages === []) {
        return;
    }

    $position = trim((string) ($options['position'] ?? 'top-right'));
    $validPositions = ['top-right', 'bottom-right', 'top-left', 'bottom-left'];
    if (!in_array($position, $validPositions, true)) {
        $position = 'top-right';
    }

    $className = 'myron-toast-region myron-toast-region--position-' . $position;
    if (($options['shellOffset'] ?? false) === true && str_starts_with($position, 'top-')) {
        $className .= ' myron-toast-region--shell-offset';
    }

    ?>
    <div class="<?= myronEscape($className) ?>" data-myron-toast-region>
      <?php foreach ($renderMessages as $message): ?>
      <?php
        $tone = myronNormalizeFlashTone((string) ($message['tone'] ?? 'info'));
        $toastClassName = 'myron-toast' . ($tone === 'info' ? '' : ' myron-toast--tone-' . $tone);
        $dismissible = (bool) ($message['dismissible'] ?? true);
        $iconName = myronFlashIconName($tone);
      ?>
      <div
        class="<?= myronEscape($toastClassName) ?>"
        role="<?= myronEscape((string) ($message['role'] ?? 'status')) ?>"
        aria-live="<?= myronEscape((string) ($message['live'] ?? 'polite')) ?>"
        data-myron-toast
        data-myron-auto-dismiss-ms="<?= myronEscape((string) max(0, (int) ($message['autoDismissMs'] ?? 0))) ?>"
        >
        <img
          class="mc-icon myron-toast__icon"
          src="<?= myronEscape(myronBuildAssetUrl('icons/bootstrap/' . $iconName . '.svg')) ?>"
          alt=""
          aria-hidden="true"
        >
        <div class="myron-toast__body">
          <?php if (trim((string) ($message['title'] ?? '')) !== ''): ?>
          <p class="myron-toast__title"><?= myronEscape((string) ($message['title'] ?? '')) ?></p>
          <?php endif; ?>
          <p class="myron-toast__message"><?= myronEscape((string) ($message['message'] ?? '')) ?></p>
        </div>
        <?php if ($dismissible): ?>
        <button class="myron-toast__dismiss" type="button" aria-label="Dismiss notification" data-myron-toast-dismiss>×</button>
        <?php endif; ?>
      </div>
      <?php endforeach; ?>
    </div>
    <?php
}
