<?php

namespace Components\Ui;

use Components\Base;

/**
 * EmailPreviewer page component.
 *
 * Renders the email preview UI (URL field, device buttons, mockups, iframes)
 * as a reusable component. All inline HTML is captured with ob_start.
 *
 * Options:
 * - url: string initial URL to load (optional)
 * - device: 'desktop'|'tablet'|'mobile' (default 'desktop')
 * - id_prefix: string unique prefix for element ids to avoid collisions (default 'ep')
 *
 */
class EmailPreviewer
{
    public static function render(array $opts = []): string
    {
        $url = isset($opts['url']) ? (string)$opts['url'] : '';
        $device = isset($opts['device']) ? (string)$opts['device'] : 'desktop';
        $idPrefix = isset($opts['id_prefix']) && $opts['id_prefix'] !== '' ? (string)$opts['id_prefix'] : 'ep';
        // Make availability of Mockup toggle optional (default: true)
        $allowMockup = array_key_exists('allow_mockup', $opts) ? (bool)$opts['allow_mockup'] : false;

        // Basic sanitation for the initial URL
        $safeUrl = '';
        if ($url !== '') {
            $u = filter_var($url, FILTER_VALIDATE_URL);
            if ($u && ((strpos($u, 'http://') === 0) || (strpos($u, 'https://') === 0))) {
                $safeUrl = $u;
            }
        }

        $overlayId = $idPrefix . '-overlay';
        $idMaster = $idPrefix . '-frame-master';
        $idPlainDesktop = $idPrefix . '-frame-plain-desktop';
        $idPlainTablet = $idPrefix . '-frame-plain-tablet';
        $idPlainMobile = $idPrefix . '-frame-plain-mobile';
        $idMockDesktop = $idPrefix . '-frame-mock-desktop';
        $idMockTablet = $idPrefix . '-frame-mock-tablet';
        $idMockMobile = $idPrefix . '-frame-mock-mobile';

        // Languages from store system
        $defaultLanguageId = \mh_session('languages_id', '2');
        $langItems = [];
        if (function_exists('mh_get_language_list')) {
            try {
                $langItems = (array)\mh_get_language_list();
            } catch (\Throwable $e) {
                $langItems = [];
            }
        }
        // Normalize and detect default id by code
        $languages = [];
        foreach ($langItems as $li) {
            if (!is_array($li)) continue;
            $id = isset($li['id']) ? (int)$li['id'] : (isset($li['languages_id']) ? (int)$li['languages_id'] : 0);
            if ($id <= 0) continue;
            $code = isset($li['code']) ? (string)$li['code'] : '';
            $text = isset($li['text']) ? (string)$li['text'] : ($code !== '' ? strtoupper($code) : ('#' . $id));
            $languages[] = ['id' => $id, 'code' => $code, 'text' => $text];
            if ($defaultLanguageId === null && $code !== '' && strtolower($code) === strtolower($defaultLanguageId)) {
                $defaultLanguageId = $id;
            }
        }
        if ($defaultLanguageId === null && !empty($languages)) {
            $defaultLanguageId = (int)$languages[0]['id'];
        }
        $languagesJson = json_encode($languages);

        ob_start();
        ?>
        <div data-email-preview-root="1"
             data-ep-id-prefix="<?= Base::h($idPrefix) ?>"
             data-ep-overlay-id="<?= Base::h($overlayId) ?>"
             data-ep-languages='<?= Base::h((string)$languagesJson, false) ?>'
             data-ep-default-language-id='<?= Base::h((string)($defaultLanguageId ?? 1), false) ?>'
             data-ep-allow-mockup='<?= Base::h($allowMockup ? '1' : '0', false) ?>'
             x-data="previewer()"
             x-init="init('<?= Base::h($safeUrl) ?>','<?= Base::h($device) ?>')"
             class="space-y-6 relative h-full">

            <!-- URL input + Load -->
            <!--
                        <div class="flex items-end gap-3 flex-wrap">
                            <div class="flex-1" style="min-width:16rem">
                                <label class="block text-sm font-medium">Email URL</label>
                                <input type="url" x-model="url"
                                       placeholder="https://example.com/email.html"
                                       class="mt-1 block w-full rounded-md border px-3 py-2 text-sm" />
                            </div>
                            <div class="flex items-center gap-2">
                                <button @click="load()" class="rounded-md bg-primary px-3 py-2 text-sm text-white">Load</button>
                                <a :href="finalSrc || '#'" target="_blank"
                                   class="rounded-md bg-gray-100 px-3 py-2 text-sm">Open</a>
                            </div>
                        </div>
            -->

            <!-- Fixed controls: left (mockup + width), right (device + language) -->
            <!-- Left: mockup toggle and width indicator -->
            <div x-show="allowMockup"
                 class="absolute mt-2 ml-2 z-20 flex items-center gap-4 opacity-70 hover:opacity-100">
                <!-- Mockup toggle (switch) -->
                <label class="flex items-center gap-2 text-xs">
                    <span class="text-gray-600">Mockup</span>
                    <span class="group relative inline-flex w-9 p-0.5 shrink-0 rounded-full bg-gray-200 inset-ring inset-ring-gray-900/5 outline-offset-2 has-focus-visible:outline-2 transition-colors duration-200 ease-in-out dark:bg-white/5 dark:inset-ring-white/10"
                          :class="showMockup ? 'bg-brand has-checked:bg-brand outline-brand dark:outline-brand' : ''">
                        <span class="size-4 rounded-full bg-white shadow-xs ring-1 ring-gray-900/5 transition-transform duration-200 ease-in-out"
                              :class="showMockup ? 'translate-x-4' : ''"></span>
                        <input type="checkbox" aria-label="Toggle mockup"
                               class="absolute inset-0 appearance-none focus:outline-hidden"
                               x-model="showMockup" @change="updateScale()"/>
                    </span>
                </label>

                <!-- Current width indicator -->
                <span class="ml-2 text-xs text-gray-500 hidden sm:inline">Width: <span
                            x-text="frameWidthDisplay"></span></span>
            </div>

            <!-- Right: device button group with language selector beneath -->
            <div class="absolute right-6 mt-2 z-20 flex flex-col items-end gap-2 opacity-60 hover:opacity-100">
                <!-- Device button group (pill tabs style) -->
                <div class="flex gap-1 rounded-full bg-muted p-1 dark:bg-muted" role="tablist" aria-orientation="horizontal">
                    <button type="button" role="tab"
                            class="group flex items-center rounded-full px-1 text-sm/7 font-medium data-selected:bg-white data-selected:ring data-selected:ring-muted/5 dark:data-selected:bg-gray-600 dark:data-selected:ring-0 dark:data-selected:inset-ring dark:data-selected:inset-ring-white/10"
                            :data-selected="device==='desktop' ? '' : null"
                            @click="setDevice('desktop')"><?php echo Base::SVG_DEVICE_DESKTOP; ?></button>
<!--
                    <button type="button" role="tab"
                            class="group flex items-center rounded-full px-4 text-sm/7 font-medium data-selected:bg-white data-selected:ring data-selected:ring-muted/5 dark:data-selected:bg-gray-600 dark:data-selected:ring-0 dark:data-selected:inset-ring dark:data-selected:inset-ring-white/10"
                            :data-selected="device==='tablet' ? '' : null"
                            @click="setDevice('tablet')">Tablet</button>
-->

                    <button type="button" role="tab"
                            class="group flex items-center rounded-full px-1 text-sm/7 font-medium data-selected:bg-white data-selected:ring data-selected:ring-muted/5 dark:data-selected:bg-gray-600 dark:data-selected:ring-0 dark:data-selected:inset-ring dark:data-selected:inset-ring-white/10"
                            :data-selected="device==='mobile' ? '' : null"
                            @click="setDevice('mobile')"><?php echo Base::SVG_DEVICE_PHONE ?></button>
                </div>

                <!-- Language selector (beneath) -->
                <div class="grid grid-cols-1 bg-white">
                    <select
                            x-model.number="languageId" @change="changeLanguage()"
                            class="col-start-1 row-start-1 h-9 appearance-none rounded-lg border-0 bg-transparent pr-7 pl-3 font-medium  sm:text-sm dark:*:bg-gray-950 focus:outline-none">
                        <template x-for="lang in languages" :key="lang.id">
                            <option :value="lang.id"
                                    x-text="lang.text || (lang.code ? lang.code.toUpperCase() : ('#'+lang.id))"></option>
                        </template>
                    </select>
                    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="currentColor" aria-hidden="true"
                         data-slot="icon"
                         class="pointer-events-none col-start-1 row-start-1 mr-2 size-4 self-center justify-self-end ">
                        <path fill-rule="evenodd"
                              d="M4.22 6.22a.75.75 0 0 1 1.06 0L8 8.94l2.72-2.72a.75.75 0 1 1 1.06 1.06l-3.25 3.25a.75.75 0 0 1-1.06 0L4.22 7.28a.75.75 0 0 1 0-1.06Z"
                              clip-rule="evenodd"></path>
                    </svg>
                </div>

                <label class="inline-flex sm:hidden items-center gap-1 text-xs bg-white/90 border border-divider px-2 py-1 rounded ">
                    <select x-model.number="languageId" @change="changeLanguage()"
                            class=" appearance-none text-xs bg-white focus:outline-none">
                        <template x-for="lang in languages" :key="lang.id">
                            <option :value="lang.id"
                                    x-text="lang.text || (lang.code ? lang.code.toUpperCase() : ('#'+lang.id))"></option>
                        </template>
                    </select>
                    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="currentColor" aria-hidden="true"
                         data-slot="icon"
                         class="pointer-events-none col-start-1 row-start-1 mr-2 size-4 self-center justify-self-end text-gray-400">
                        <path fill-rule="evenodd"
                              d="M4.22 6.22a.75.75 0 0 1 1.06 0L8 8.94l2.72-2.72a.75.75 0 1 1 1.06 1.06l-3.25 3.25a.75.75 0 0 1-1.06 0L4.22 7.28a.75.75 0 0 1 0-1.06Z"
                              clip-rule="evenodd"></path>
                    </svg>
                </label>
            </div>

            <!-- Main preview area -->
            <div class="relative overflow-hidden h-full">

                <!-- Pattern background -->
                <svg class="absolute inset-0 rounded-xl size-full stroke-divider/90 dark:stroke-muted/10 pointer-events-none z-0" fill="none" aria-hidden="true">
                    <defs>
                        <pattern id="pattern-<?php echo Base::h($idPrefix); ?>" x="0" y="0" width="8" height="8" patternUnits="userSpaceOnUse">
                            <path d="M-1 5L5 -1M3 9L8.5 3.5" stroke-width="0.5"></path>
                        </pattern>
                    </defs>
                    <rect stroke="none" fill="url(#pattern-<?php echo Base::h($idPrefix); ?>)" width="100%" height="100%"></rect>
                </svg>

                <!-- Loading overlay over the preview area -->
                <?php echo Base::loaderOverlay($overlayId, 'z-20', ''); ?>
                <div class="mx-auto relative z-10 h-full" :style="frameStyle">

                    <!-- Hidden master iframe (load once per language) -->
                    <iframe id="<?= Base::h($idMaster) ?>" class="hidden"
                            sandbox="allow-same-origin allow-forms allow-scripts"></iframe>

                    <!-- Plain iframes -->
                    <div x-show="!showMockup || !allowMockup" class="h-full">
                        <iframe id="<?= Base::h($idPlainDesktop) ?>" data-preview="desktop"
                                class="block w-full  h-full bg-white"></iframe>
                        <iframe id="<?= Base::h($idPlainTablet) ?>" data-preview="tablet"
                                class="hidden  bg-white"></iframe>
                        <iframe id="<?= Base::h($idPlainMobile) ?>" data-preview="mobile"
                                class="hidden  bg-white"></iframe>
                    </div>

                    <!-- Mockups -->
                    <div x-show="showMockup && allowMockup" :style="mockupScaleStyle">
                        <div x-show="device==='desktop'">
                            <?= EmailPreviewMockups::desktop(
                                    '<iframe id="' . Base::h($idMockDesktop) . '" data-preview="desktop" class="w-full h-full bg-white"></iframe>'
                            ) ?>
                        </div>
                        <div x-show="device==='tablet'">
                            <?= EmailPreviewMockups::tablet(
                                    '<iframe id="' . Base::h($idMockTablet) . '" data-preview="tablet" class="w-full h-full bg-white"></iframe>'
                            ) ?>
                        </div>
                        <div x-show="device==='mobile'">
                            <?= EmailPreviewMockups::mobile(
                                    '<iframe id="' . Base::h($idMockMobile) . '" data-preview="mobile" class="w-full h-full bg-white"></iframe>'
                            ) ?>
                        </div>
                    </div>

                </div>
            </div>

            <!-- Bottom-right vertical scale controls (only for mockup) -->
            <div x-show="showMockup && allowMockup"
                 class="fixed right-12 bottom-8 z-20 flex flex-col items-center gap-2">
                <button @click="incScale()" type="button"
                        class="size-9 rounded-full bg-white shadow ring-1 ring-gray-200 flex items-center justify-center hover:bg-gray-50">
                    <span class="size-5 text-gray-700"><?= Base::SVG_PLUS ?></span>
                </button>
                <div class="text-xs font-medium text-gray-700 bg-white/90 rounded px-2 py-1"
                     x-text="scalePercent"></div>
                <button @click="decScale()" type="button"
                        class="size-9 rounded-full bg-white shadow ring-1 ring-gray-200 flex items-center justify-center hover:bg-gray-50">
                    <span class="size-5 text-gray-700"><?= Base::SVG_MINUS ?></span>
                </button>
            </div>

            <script>
                function previewer() {
                    return {
                        // Configurable identifiers to avoid collisions when used multiple times
                        idPrefix: null,
                        overlayId: null,

                        url: '',
                        device: 'desktop',
                        languageId: null,
                        languages: [],

                        sizes: {
                            desktop: {width: '100%', maxWidth: '100%'},
                            tablet: {width: '768px', maxWidth: '100%'},
                            mobile: {width: '375px', maxWidth: '100%'},
                        },

                        showMockup: false,
                        allowMockup: true,

                        // Scale options for mockup view (percentages)
                        scaleOptions: [
                            {value: 0.5, label: '50%'},
                            {value: 0.7, label: '70%'},
                            {value: 0.9, label: '90%'},
                            {value: 1, label: '100%'},
                        ],

                        // Default scale when mockup is enabled
                        scale: 0.7,

                        get ids() {
                            // Match the server-rendered ids exactly
                            const p = this.idPrefix || 'ep';
                            return {
                                master: p + '-frame-master',
                                plainDesktop: p + '-frame-plain-desktop',
                                plainTablet: p + '-frame-plain-tablet',
                                plainMobile: p + '-frame-plain-mobile',
                                mockDesktop: p + '-frame-mock-desktop',
                                mockTablet: p + '-frame-mock-tablet',
                                mockMobile: p + '-frame-mock-mobile',
                            };
                        },

                        get frameWidthDisplay() {
                            return this.sizes[this.device].width;
                        },

                        get finalSrc() {
                            if (!this.url) return 'about:blank';
                            try {
                                const u = new URL(this.url);
                                if (this.languageId) {
                                    u.searchParams.set('lng_id', String(this.languageId));
                                }
                                return u.toString();
                            } catch (e) {
                                return this.url;
                            }
                        },

                        get frameStyle() {
                            const size = this.sizes[this.device];
                            // Smoothly animate width changes when toggling device sizes
                            // Use inline transition to avoid relying on Tailwind safelisting
                            return `width:${size.width}; max-width:${size.maxWidth}; transition: width 500ms ease-in-out, max-width 500ms ease-in-out;`;
                        },

                        // Style applied to the mockup container to scale device + iframe
                        get mockupScaleStyle() {
                            const s = Number(this.scale);
                            if (!this.showMockup || !Number.isFinite(s) || s <= 0) return '';
                            return `transform: scale(${s}); transform-origin: top center;`;
                        },

                        get scalePercent() {
                            const s = Number(this.scale);
                            if (!Number.isFinite(s) || s <= 0) return '100%';
                            return Math.round(s * 100) + '%';
                        },

                        init(u, d) {
                            // pick configuration from root attributes
                            try {
                                const root = this.$root;
                                this.idPrefix = root.getAttribute('data-ep-id-prefix') || 'ep';
                                this.overlayId = root.getAttribute('data-ep-overlay-id') || (this.idPrefix + '-overlay');
                                const langsAttr = root.getAttribute('data-ep-languages') || '[]';
                                try {
                                    this.languages = JSON.parse(langsAttr) || [];
                                } catch (parseErr) {
                                    this.languages = [];
                                }
                                const defIdAttr = root.getAttribute('data-ep-default-language-id') || '0';
                                const defId = parseInt(defIdAttr, 10);
                                this.languageId = Number.isFinite(defId) && defId > 0 ? defId : (this.languages[0]?.id || null);
                                const allowMockAttr = root.getAttribute('data-ep-allow-mockup');
                                this.allowMockup = allowMockAttr === '1' || allowMockAttr === 'true' || allowMockAttr === 'yes';
                            } catch (e) {
                                this.idPrefix = 'ep';
                                this.overlayId = 'ep-overlay';
                            }

                            // Listen for external URL set events from integrations (e.g., modal)
                            try {
                                this.$root.addEventListener('mb:email-preview:set-url', (ev) => {
                                    try {
                                        const u2 = ev && ev.detail ? (ev.detail.url || '') : '';
                                        if (u2) this.setUrlAndLoad(u2);
                                    } catch (e2) {
                                    }
                                });
                            } catch (e3) {
                            }

                            this.url = u || '';
                            this.device = this.sizes[d] ? d : 'desktop';
                            if (!this.allowMockup) this.showMockup = false;
                            if (this.url) this.load();
                        },

                        // External API for integration: set URL and load
                        setUrlAndLoad(u) {
                            this.url = u || '';
                            this.load();
                        },

                        // load once → only into master frame
                        load() {
                            const master = document.getElementById(this.ids.master);
                            const src = this.finalSrc;
                            // Show overlay only for real URLs
                            if (src && src !== 'about:blank') this.showLoader();
                            if (!master) return;
                            master.onload = () => {
                                try {
                                    this.copyMasterToPreviews();
                                } finally {
                                    this.hideLoader();
                                }
                            };
                            master.onerror = () => {
                                this.hideLoader();
                            };
                            master.src = src;
                        },

                        // Copy DOM from master iframe → visible device frames
                        copyMasterToPreviews() {
                            const master = document.getElementById(this.ids.master);
                            const doc = master ? master.contentDocument : null;
                            if (!doc) return;

                            const html = doc.documentElement.cloneNode(true);

                            this.$root.querySelectorAll('[data-preview]').forEach(frame => {
                                const fd = frame.contentDocument;
                                if (!fd) return;
                                fd.open();
                                fd.write(html.outerHTML);
                                fd.close();
                            });
                        },

                        setDevice(d) {
                            this.device = d;
                        },

                        changeLanguage() {
                            this.load();
                        },

                        updateScale() {
                            // normalize scale value
                            const s = Number(this.scale);
                            if (!Number.isFinite(s) || s <= 0) this.scale = 1;
                        },

                        // Increase/decrease scale using predefined options
                        incScale() {
                            try {
                                const opts = this.scaleOptions.map(o => o.value).sort((a, b) => a - b);
                                const curr = Number(this.scale);
                                let next = opts[opts.length - 1];
                                for (let i = 0; i < opts.length; i++) {
                                    if (opts[i] > curr + 1e-6) {
                                        next = opts[i];
                                        break;
                                    }
                                }
                                this.scale = next;
                                this.updateScale();
                            } catch (e) {
                                this.scale = 1;
                            }
                        },
                        decScale() {
                            try {
                                const opts = this.scaleOptions.map(o => o.value).sort((a, b) => a - b);
                                const curr = Number(this.scale);
                                let prev = opts[0];
                                for (let i = opts.length - 1; i >= 0; i--) {
                                    if (opts[i] < curr - 1e-6) {
                                        prev = opts[i];
                                        break;
                                    }
                                }
                                this.scale = prev;
                                this.updateScale();
                            } catch (e) {
                                this.scale = 1;
                            }
                        },

                        showLoader() {
                            const o = document.getElementById(this.overlayId);
                            if (!o) return;
                            if (window.MBLoader && MBLoader.show) MBLoader.show(o); else o.classList.remove('hidden');
                        },

                        hideLoader() {
                            const o = document.getElementById(this.overlayId);
                            if (!o) return;
                            if (window.MBLoader && MBLoader.hide) MBLoader.hide(o); else o.classList.add('hidden');
                        },

                        // Button group classes for device buttons
                        btnGroupClass(d, pos) {
                            const base = 'px-1.5 py-1 text-xs focus:outline-hidden';
                            const selected = this.device === d;
                            const shape = pos === 'first' ? 'rounded-l-md border-r border-divider' : (pos === 'last' ? 'rounded-r-md border-l' : 'border-l border-r');
                            const state = selected ? ' bg-secondary text-white' : ' bg-white text-gray-700 hover:bg-gray-50';
                            return base + ' ' + shape + state;
                        }
                    }
                }
            </script>

        </div>
        <?php
        return ob_get_clean();
    }
}
