<?php
// components/Modal.php
namespace Components;

class Modal extends Base
{
    /**
     * Get the SVG icon for a given type, wrapped in standard Tailwind UI classes.
     */
    public static function getIconForType(string $type): string
    {
        switch ($type) {
            case 'alert':
                return '<div class="mx-auto flex h-12 w-12 shrink-0 items-center justify-center rounded-full bg-danger sm:h-12 sm:w-12 [&_svg]:size-full"><span class="h-8 w-8 text-danger [&_svg]:size-full">' . self::SVG_EXCLAMATION_TRIANGLE . '</span></div>';
            case 'warning':
                return '<div class="mx-auto flex h-12 w-12 shrink-0 items-center justify-center rounded-full bg-warning sm:h-12 sm:w-12 [&_svg]:size-full"><span class="h-8 w-8 text-warning [&_svg]:size-full">' . self::SVG_EXCLAMATION_TRIANGLE . '</span></div>';
            case 'success':
                return '<div class="mx-auto flex h-12 w-12 shrink-0 items-center justify-center rounded-full bg-green-100 sm:h-12 sm:w-12 [&_svg]:size-full dark:bg-green-900/30"><span class="h-8 w-8 text-green-600 [&_svg]:size-full dark:text-green-400">' . self::SVG_CHECK_ROUNDED . '</span></div>';
            case 'info':
                return '<div class="mx-auto flex h-12 w-12 shrink-0 items-center justify-center rounded-full bg-info sm:h-12 sm:w-12 [&_svg]:size-full"><span class="h-8 w-8 text-info [&_svg]:size-full">' . self::SVG_INFORMATION_CIRCLE . '</span></div>';
            case 'notice':
                return '<div class="mx-auto flex h-12 w-12 shrink-0 items-center justify-center rounded-full bg-brand-100 sm:h-12 sm:w-12 [&_svg]:size-full"><span class="h-8 w-8 text-brand-600 [&_svg]:size-full">' . self::SVG_INFORMATION_CIRCLE . '</span></div>';
            default:
                return '';
        }
    }

    /**
     * Get all type icons as a JSON-encodable array.
     */
    public static function getTypeIconsMap(): array
    {
        return [
            'alert'   => self::getIconForType('alert'),
            'warning' => self::getIconForType('warning'),
            'info'    => self::getIconForType('info'),
            'success' => self::getIconForType('success'),
            'notice'  => self::getIconForType('notice'),
        ];
    }

    /**
     * Render the configuration modal markup.
     * Options:
     * - id | modalId: string element id of the modal root (default: 'config-modal')
     * - style: 'default' | 'ai' | 'email_preview' (default: 'default')
     * - backdrop: 'default' | 'none' (default: 'default')
     *   - 'default': semi-transparent background behind the dialog
     *   - 'none': no background color on the backdrop (fully transparent)
     */
    public static function render(array $opts = []): string
    {
        $modalId = isset($opts['id']) && $opts['id'] !== ''
                ? (string)$opts['id']
                : (isset($opts['modalId']) && $opts['modalId'] !== '' ? (string)$opts['modalId'] : 'config-modal');

        $style = isset($opts['style']) ? (string)$opts['style'] : 'default';

        $wrapperId = $modalId . '-wrapper';
        $panelId = $modalId . '-panel';
        $headerId = $modalId . '-header';
        $headerToolbarId = $modalId . '-header-toolbar';
        $headerToolbarRightId = $modalId . '-header-toolbar-right';
        $titleId = $modalId . '-title';
        $headerCloseId = $modalId . '-header-close';
        $headerExtrasId = $modalId . '-header-extras';
        $headerIconId = $modalId . '-header-icon';
        $floatingCloseId = $modalId . '-floating-close';
        $bodyId = $modalId . '-body';
        $iframeId = $modalId . '-iframe';
        $footerId = $modalId . '-footer';
        $loadingId = $modalId . '-loading';

        // Backdrop & panel defaults
        $backDropCss = 'bg-black/10 dark:bg-gray-900/50';
        $dialogPanelCss = 'group/modal-panel relative w-full transform overflow-hidden rounded-2xl bg-white text-left shadow-xl transition-all dark:bg-gray-800 max-w-2xl flex flex-col max-h-[95vh] data-closed:opacity-0 data-closed:scale-95 data-enter:animate-modal-overswing data-leave:duration-200 data-leave:ease-in';

        $backdropMode = isset($opts['backdrop']) ? (string)$opts['backdrop'] : 'default';
        $popin = isset($opts['popin']) && (bool)$opts['popin'];
        $scrollHints = isset($opts['scroll_hints']) ? (bool)$opts['scroll_hints'] : ($style !== 'confirm');


        // Escaped IDs
        $modalIdEsc = self::h($modalId, false);
        $wrapperIdEsc = self::h($wrapperId, false);
        $panelIdEsc = self::h($panelId, false);
        $headerIdEsc = self::h($headerId, false);
        $headerToolbarIdEsc = self::h($headerToolbarId, false);
        $headerToolbarRightIdEsc = self::h($headerToolbarRightId, false);
        $titleIdEsc = self::h($titleId, false);
        $headerCloseIdEsc = self::h($headerCloseId, false);
        $headerExtrasIdEsc = self::h($headerExtrasId, false);
        $headerIconIdEsc = self::h($headerIconId, false);
        $floatingCloseIdEsc = self::h($floatingCloseId, false);
        $bodyIdEsc = self::h($bodyId, false);
        $iframeIdEsc = self::h($iframeId, false);
        $footerIdEsc = self::h($footerId, false);
        $loadingIdEsc = self::h($loadingId, false);

        // Loader HTML
        $loader = self::loaderOverlay($loadingId, 'z-10');

        $scrollHintsHtml = $scrollHints ? self::scrollHintsHtml([
            'top_from' => 'from-canvas-modal',
            'bottom_from' => 'from-canvas-modal',
        ]) : '';

        $scrollHintsHtmlPreview = $scrollHints ? self::scrollHintsHtml() : '';

        // Optional: allow callers to control visibility of the built-in
        // close button via data-close-button on the dialog element.
        // Defaults to "true" to preserve existing behavior.
        $closeButtonEnabled = !array_key_exists('close_button', $opts) || (bool)$opts['close_button'];

        // Optional: make the modal persistent / "exclusive" so it can only be
        // closed via an explicit button (no Escape key, no backdrop click).
        // Defaults to "true" (dismissible) to preserve existing behavior.
        $dismissible = !array_key_exists('dismissible', $opts) || (bool)$opts['dismissible'];

        switch ($style) {
            case 'ai':
                // Keep previous behavior: no light-mode backdrop, but a subtle dark-mode overlay
                $backDropCss = '';
                $dialogPanelCss = 'flex-1 relative min-h-[80vh] max-h-[95vh]';
                $loader = '';
                break;
            case 'editor_inline':
                $backDropCss = '';
                $dialogPanelCss .= ' ring ring-divider';
                break;
            case 'confirm':
                $dialogPanelCss = 'group/modal-panel relative w-full transform overflow-hidden rounded-2xl bg-white text-center shadow-xl transition-all dark:bg-gray-800 max-w-md flex flex-col max-h-[95vh] data-closed:opacity-0 data-closed:scale-95 data-enter:animate-modal-overswing data-leave:duration-200 data-leave:ease-in';
                break;
            case 'email_preview':
                break;
            case 'default':
            default:
                break;
        }

        // Allow callers to request a fully transparent backdrop independent of style
        if ($backdropMode === 'none') {
            $backDropCss = '';
        }


        if ($popin) {
            $dialogPanelCss = str_replace('data-enter:animate-modal-overswing', '', $dialogPanelCss);
            $dialogPanelCss .= ' data-enter:animate-popin';
        }

        ob_start();
        ?>
        <el-dialog>
            <dialog id="<?= $modalIdEsc; ?>" aria-labelledby="<?= $titleIdEsc; ?>" data-style="<?= self::h($style, false) ?>"
                    data-close-button="<?= $closeButtonEnabled ? 'true' : 'false'; ?>"
                    data-dismissible="<?= $dismissible ? 'true' : 'false'; ?>"
                    data-popin="<?= $popin ? 'true' : 'false'; ?>"
                    data-scroll-hints="<?= $scrollHints ? 'true' : 'false'; ?>"
                    class="fixed inset-0 size-auto max-h-none max-w-none overflow-hidden bg-transparent backdrop:bg-transparent">
                <el-dialog-backdrop
                        class="fixed inset-0 <?= $backDropCss; ?> transition-opacity data-closed:opacity-0 data-enter:duration-300 data-enter:ease-out data-leave:duration-200 data-leave:ease-in"></el-dialog-backdrop>
                <div id="<?= $wrapperIdEsc; ?>" tabindex="0"
                     class="flex min-h-full items-end justify-center p-4 text-center focus:outline-none sm:items-center sm:p-0">
                    <el-dialog-panel id="<?= $panelIdEsc; ?>" class="<?= $dialogPanelCss; ?>"
                        <?php if ($scrollHints): ?>
                        <?= self::scrollHintsData(); ?>
                        <?php endif; ?>
                    >
                        <?php if ($style === 'ai'): ?>
                        <div>
                            <div class="absolute -inset-3">
                                <div class="w-full h-full mx-auto opacity-20 blur-sm filter animate-pulse-opacity-and-rotate mbz-ai-gradient"></div>
                            </div>
                            <div class="group/modal-panel p-8 relative w-full transform overflow-hidden rounded-2xl border border-gray-200 bg-white text-left shadow-xl transition-all dark:bg-gray-800 max-w-2xl flex flex-col max-h-[95vh]">
                                <?php endif; ?>

                                <!-- Header (conditionally shown when a title is provided) -->
                                <?= self::renderHeader([
                                        'style' => $style,
                                        'modalId' => $modalIdEsc,
                                        'headerId' => $headerIdEsc,
                                        'headerToolbarId' => $headerToolbarIdEsc,
                                        'headerToolbarRightId' => $headerToolbarRightIdEsc,
                                        'titleId' => $titleIdEsc,
                                        'headerCloseId' => $headerCloseIdEsc,
                                        'headerExtrasId' => $headerExtrasIdEsc,
                                        'headerIconId' => $headerIconIdEsc,
                                        'floatingCloseId' => $floatingCloseIdEsc,
                                ]); ?>


                                <!-- Body: either HTMX target or isolated iframe -->
                                <?php if ($style === 'email_preview' || $style === 'web_preview') { ?>
                                    <div class="relative flex-1 flex flex-col min-h-0">
                                        <div class="overflow-auto p-6 pt-0 flex-1 min-h-0" data-mb-body-extra=""
                                            <?php if ($scrollHints): ?>
                                                x-ref="scroller"
                                                @scroll.passive="update()"
                                            <?php endif; ?>>
                                            <div id="<?= $bodyIdEsc; ?>" class="h-full">
                                                <?php
                                                // Render the page component with a modal-specific id prefix; URL will be injected by JS via data-url.
                                                if ($style === 'email_preview') {
                                                    if (class_exists('Components\\Ui\\EmailPreviewer')) {
                                                        echo \Components\Ui\EmailPreviewer::render([
                                                            'url' => '',
                                                            'device' => 'desktop',
                                                            'modal_id' => $modalId,
                                                            'id_prefix' => $modalId . '-ep',
                                                        ]);
                                                    }
                                                } else {
                                                    if (class_exists('Components\\Ui\\WebPreviewer')) {
                                                        echo \Components\Ui\WebPreviewer::render([
                                                            'url' => '',
                                                            'device' => 'desktop',
                                                            'modal_id' => $modalId,
                                                            'id_prefix' => $modalId . '-wp',
                                                        ]);
                                                    }
                                                }
                                                ?>
                                            </div>
                                            <!-- Keep iframe present but hidden for API parity; not used in preview styles -->
                                            <iframe id="<?= $iframeIdEsc; ?>" src="about:blank" title="Modal content"
                                                    class="hidden w-full border-0 bg-white dark:bg-gray-900 h-full"></iframe>
                                        </div>
                                        <?= $scrollHintsHtmlPreview ?>
                                    </div>
                                <?php } else {
                                    $bodyClass = 'max-h-[90vh] overflow-auto p-6';
                                    if ($style === 'confirm') {
                                        $bodyClass = 'max-h-[90vh] overflow-auto px-6 pb-2 pt-0';
                                    }
                                    ?>
                                    <div class="relative flex-1 flex flex-col min-h-0 bg-canvas-modal">
                                        <div class="<?= $bodyClass; ?>"
                                            <?php if ($scrollHints): ?>
                                                x-ref="scroller"
                                                @scroll.passive="update()"
                                            <?php endif; ?>>
    
                                            <!-- Loading overlay for iframe/htmx mode -->
                                            <?= $loader ?>
                                            <!-- HTMX content target -->
                                            <div id="<?= $bodyIdEsc; ?>"></div>
                                            <!-- Isolated URL content -->
                                            <iframe id="<?= $iframeIdEsc; ?>" src="about:blank" title="Modal content"
                                                    class="hidden h-[70vh] w-full border-0 bg-white dark:bg-gray-900"></iframe>
                                        </div>
                                        <?= $scrollHintsHtml ?>
                                    </div>
                                <?php } ?>

                                <!-- Optional footer slot (empty by default) -->
                                <?php
                                $footerClass = 'hidden shrink-0 border-t border-divider sm:p-4 dark:border-white/10';
                                if ($style === 'confirm') {
                                    $footerClass = 'hidden shrink-0 sm:p-4 dark:border-white/10';
                                }
                                ?>
                                <div id="<?= $footerIdEsc; ?>" class="<?= $footerClass ?>"></div>

                                <?php if ($style === 'ai'): ?>
                            </div>
                        </div>
                    <?php endif; ?>
                    </el-dialog-panel>
                </div>
            </dialog>
        </el-dialog>
        <?php
        return ob_get_clean();
    }

    /**
     * Render the shared modal header markup.
     *
     * The header is initially hidden and is shown by JS when a non-empty
     * data-title attribute is present on the dialog element. A dedicated
     * "extras" container is provided so components like the email previewer
     * can teleport controls (device switcher, language selector) into the
     * header without coupling Modal to those components.
     *
     * @param array{style?:string,modalId:string,headerId:string,headerToolbarId?:string,headerToolbarRightId?:string,titleId:string,headerCloseId:string,headerExtrasId:string,headerIconId:string} $opts
     */
    private static function renderHeader(array $opts): string
    {
        $style = isset($opts['style']) ? (string)$opts['style'] : 'default';
        $modalIdEsc = (string)($opts['modalId'] ?? 'config-modal');
        $headerIdEsc = (string)($opts['headerId'] ?? 'config-modal-header');
        $headerToolbarIdEsc = (string)($opts['headerToolbarId'] ?? 'config-modal-header-toolbar');
        $headerToolbarRightIdEsc = (string)($opts['headerToolbarRightId'] ?? 'config-modal-header-toolbar-right');
        $titleIdEsc = (string)($opts['titleId'] ?? 'config-modal-title');
        $headerCloseEsc = (string)($opts['headerCloseId'] ?? 'config-modal-header-close');
        $headerExtrasId = (string)($opts['headerExtrasId'] ?? 'config-modal-header-extras');
        $headerIconIdEsc = (string)($opts['headerIconId'] ?? 'config-modal-header-icon');
        $floatingCloseIdEsc = (string)($opts['floatingCloseId'] ?? 'config-modal-floating-close');

        // Base header classes; we keep them compact so the body can use as
        // much of the dialog as possible. We use flex + justify-between so
        // that callers can treat the three logical areas as:
        //   - left:  title + extras
        //   - center: centered toolbar (e.g. language tabs)
        //   - right:  right toolbar + close button
        $headerClasses = 'hidden flex items-center justify-between border-b border-divider px-4 py-4 dark:border-white/10';
        if ($style === 'email_preview') {
            $headerClasses = 'hidden flex items-center justify-between border-b border-divider px-4 py-2 dark:border-white/10';
        }
        if ($style === 'confirm') {
            $headerClasses = 'hidden flex flex-col items-center justify-center px-6 pt-4 pb-0 dark:border-white/10 relative';
        }

        ob_start();
        ?>
        <div id="<?= $headerIdEsc; ?>" class="<?= self::h($headerClasses, false); ?>">
            <!-- Left: title + inline extras (e.g. EmailEditor status block). This is the logical "start" area. -->
            <div class="<?= $style === 'confirm' ? 'min-w-0 flex flex-col items-center gap-4' : 'min-w-0 shrink-0 flex items-center gap-3' ?>">
                <div id="<?= $headerIconIdEsc; ?>" class="hidden"></div>
                <h1 id="<?= $titleIdEsc; ?>"
                    class="<?= $style === 'confirm' ? 'text-xl font-medium text-secondary dark:text-white text-center mt-1' : 'text-sm font-medium text-secondary dark:text-white text-nowrap' ?>"></h1>
                <!-- Optional header extras target: used by components via x-teleport -->
                <div id="<?= $headerExtrasId; ?>" class="flex items-center gap-3"></div>
            </div>

            <!-- Center: toolbar container; typically used for language tabs or preview controls. -->
            <?php if ($style !== 'confirm'): ?>
            <div class="flex-1 flex justify-center min-w-0 overflow-hidden">
                <div id="<?= $headerToolbarIdEsc; ?>" class="min-w-0"></div>
            </div>
            <?php endif; ?>

            <!-- Right: optional right toolbar container + close button -->
            <div class="<?= $style === 'confirm' ? 'absolute right-4 top-4' : 'ml-3 shrink-0 flex items-center gap-3 justify-end' ?>">
                <?php if ($style !== 'confirm'): ?>
                <div id="<?= $headerToolbarRightIdEsc; ?>"></div>
                <?php endif; ?>
                <button id="<?= $headerCloseEsc; ?>" type="button" command="close" commandfor="<?= $modalIdEsc; ?>"
                        class="relative rounded-md text-gray-400 hover:text-gray-600 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-brand dark:hover:text-white dark:focus-visible:outline-brand-500">
                    <span class="absolute -inset-2.5"></span>
                    <span class="sr-only">Close modal</span>
                    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" aria-hidden="true"
                         class="size-6">
                        <path d="M6 18 18 6M6 6l12 12" stroke-linecap="round" stroke-linejoin="round"/>
                    </svg>
                </button>
            </div>
        </div>
        <!-- Floating close button (used when no header/title) -->
        <button id="<?= $floatingCloseIdEsc; ?>" type="button" command="close" commandfor="<?= $modalIdEsc; ?>"
                class="hidden absolute right-2 top-2 z-100 rounded-md bg-white/70 p-1 text-gray-600 hover:bg-white hover:text-gray-900 dark:bg-gray-700/70 dark:text-gray-200 dark:hover:bg-gray-700">
            <span class="sr-only">Close modal</span>
            <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" aria-hidden="true"
                 class="size-6">
                <path d="M6 18 18 6M6 6l12 12" stroke-linecap="round" stroke-linejoin="round"/>
            </svg>
        </button>
        <?php
        return ob_get_clean();
    }
}
