(function () {
    var DESIGN_WIDTH = 1080;
    var MAX_PAGE_WIDTH = 768;
    var LALU_COIN_IMAGE = '../../common/png/lalu-coin.png';
    var REWARD_FIRST_TOP = 1816;
    var REWARD_PANEL_GAP = 56;
    var REWARD_GRID_TOP = 220;
    var REWARD_CARD_MIN_HEIGHT = 264;
    var REWARD_GRID_ROW_GAP = 24;
    var REWARD_PANEL_BOTTOM_PADDING = 80;
    var REWARD_STAGE_BOTTOM_PADDING = 133;
    var REWARD_MIN_PANEL_HEIGHT = 320;
    var PLAZA_VISIBLE_ROWS = 4;
    var PLAZA_ROW_HEIGHT = 199;
    var PLAZA_ROW_GAP = 24;
    var PLAZA_SECONDS_PER_ROW = 3.2;
    var PLAZA_FEED_LIMIT = 20;
    var STORAGE_KEY = 'hy_cp_activity_end_at';
    var stageHeights = {
        plaza: 4283,
        rank: 3670,
        rewards: 4797,
    };
    var rewardStageHeight = stageHeights.rewards;
    var activeTab = 'rank';
    var countdownEndAt = 0;
    var countdownTimer = 0;
    var activityData = {
        plazaRows: [],
        previousRows: [],
        rank: [],
        rewards: null,
        periodEndMS: 0,
    };

    var viewport = document.getElementById('appViewport');
    var page = document.getElementById('page');
    var stage = document.querySelector('.stage');
    var stageWrap = document.getElementById('stageWrap');
    var tabContent = document.getElementById('tabContent');
    var copyright = document.querySelector('.copyright');
    var tabs = Array.prototype.slice.call(document.querySelectorAll('.tab'));

    var mockData = {
        rewards: [
            {
                crown: 'crown-gold.png',
                items: [
                    { key: 'cp.rewardMedal7', noteKey: 'cp.rewardMedalNote' },
                    { key: 'cp.rewardHonorBanner7' },
                    { key: 'cp.rewardHeadwear7' },
                    { key: 'cp.rewardMount7' },
                    { key: 'cp.rewardCoins20000' },
                    { key: 'cp.rewardDuke7' },
                ],
            },
            {
                crown: 'crown-silver.png',
                items: [
                    { key: 'cp.rewardMedal7', noteKey: 'cp.rewardMedalNote' },
                    { key: 'cp.rewardHonorBanner7' },
                    { key: 'cp.rewardMount7' },
                    { key: 'cp.rewardCoins20000' },
                    { key: 'cp.rewardMarquis7' },
                ],
            },
            {
                crown: 'crown-bronze.png',
                items: [
                    { key: 'cp.rewardMedal7', noteKey: 'cp.rewardMedalNote' },
                    { key: 'cp.rewardHonorBanner7' },
                    { key: 'cp.rewardCoins10000' },
                    { key: 'cp.rewardCount7' },
                ],
            },
        ],
    };

    function t(key, fallback) {
        if (window.HyAppI18n && window.HyAppI18n.t) {
            return window.HyAppI18n.t(key, fallback);
        }
        return fallback || key;
    }

    function escapeHTML(value) {
        return String(value == null ? '' : value)
            .replace(/&/g, '&amp;')
            .replace(/</g, '&lt;')
            .replace(/>/g, '&gt;')
            .replace(/"/g, '&quot;')
            .replace(/'/g, '&#39;');
    }

    function twoDigits(value) {
        return String(Math.max(0, value)).padStart(2, '0');
    }

    function resolveFallbackEndAt() {
        var params = new URLSearchParams(window.location.search || '');
        var explicitEnd = Date.parse(
            params.get('end_at') || params.get('endAt') || ''
        );
        if (Number.isFinite(explicitEnd) && explicitEnd > Date.now())
            return explicitEnd;

        try {
            var cached = Number(window.localStorage.getItem(STORAGE_KEY));
            if (Number.isFinite(cached) && cached > Date.now()) return cached;
            var fallback =
                Date.now() +
                2 * 86400 * 1000 +
                2 * 3600 * 1000 +
                2 * 60 * 1000 +
                2 * 1000;
            window.localStorage.setItem(STORAGE_KEY, String(fallback));
            return fallback;
        } catch (error) {
            return (
                Date.now() +
                2 * 86400 * 1000 +
                2 * 3600 * 1000 +
                2 * 60 * 1000 +
                2 * 1000
            );
        }
    }

    function getTimeParts() {
        var diff = Math.max(0, countdownEndAt - Date.now());
        var totalSeconds = Math.floor(diff / 1000);
        return {
            days: Math.floor(totalSeconds / 86400),
            hours: Math.floor((totalSeconds % 86400) / 3600),
            minutes: Math.floor((totalSeconds % 3600) / 60),
            seconds: totalSeconds % 60,
        };
    }

    function updateCountdown() {
        var parts = getTimeParts();
        Object.keys(parts).forEach(function (key) {
            document
                .querySelectorAll('[data-count="' + key + '"]')
                .forEach(function (node) {
                    node.textContent = twoDigits(parts[key]);
                });
        });
    }

    function renderPanel(className, top, height, bodyHTML) {
        return [
            '<section class="ornate-panel ',
            className,
            '" style="top:',
            top,
            'px;height:',
            height,
            'px">',
            '<img class="panel-top" src="./assets/panel-top.webp" alt="" aria-hidden="true" />',
            '<div class="panel-mid" aria-hidden="true"></div>',
            '<img class="panel-bottom" src="./assets/panel-bottom.webp" alt="" aria-hidden="true" />',
            '<div class="panel-body">',
            bodyHTML,
            '</div>',
            '</section>',
        ].join('');
    }

    function estimateRewardPanelHeight(section) {
        var count =
            section && Array.isArray(section.items) ? section.items.length : 0;
        var rows = count > 0 ? Math.ceil(count / 3) : 0;
        var gridHeight =
            rows > 0
                ? rows * REWARD_CARD_MIN_HEIGHT +
                  Math.max(0, rows - 1) * REWARD_GRID_ROW_GAP
                : 0;
        return Math.max(
            REWARD_MIN_PANEL_HEIGHT,
            REWARD_GRID_TOP + gridHeight + REWARD_PANEL_BOTTOM_PADDING
        );
    }

    function renderAvatar(className, avatar) {
        if (!avatar) return '';
        return [
            '<div class="avatar ',
            className,
            '">',
            '<img src="',
            escapeHTML(avatar),
            '" alt="" />',
            '</div>',
        ].join('');
    }

    function renderCPRow(row) {
        var center =
            row.type === 'score'
                ? [
                      '<img class="score-heart" src="./assets/score-heart.png" alt="" aria-hidden="true" />',
                      '<strong class="score-value">',
                      escapeHTML(row.score),
                      '</strong>',
                  ].join('')
                : [
                      '<div class="gift-center">',
                      '<img src="./assets/gift-plane.png" alt="" aria-hidden="true" />',
                      '</div>',
                  ].join('');

        return [
            '<article class="cp-row">',
            renderAvatar('avatar-left', row.leftAvatar),
            renderAvatar('avatar-right', row.rightAvatar),
            '<span class="name name-left">',
            '<bdi>',
            escapeHTML(row.leftName),
            '</bdi>',
            '</span>',
            '<span class="name name-right">',
            '<bdi>',
            escapeHTML(row.rightName),
            '</bdi>',
            '</span>',
            '<img class="deco-line deco-left" src="./assets/deco-line.png" alt="" aria-hidden="true" />',
            '<img class="deco-line deco-right" src="./assets/deco-line.png" alt="" aria-hidden="true" />',
            center,
            '</article>',
        ].join('');
    }

    function renderPlazaCarousel(rows) {
        var sourceRows = Array.isArray(rows) ? rows : [];
        var shouldLoop = sourceRows.length > PLAZA_VISIBLE_ROWS;
        var rowHTML = sourceRows.map(renderCPRow).join('');
        var loopDistance =
            sourceRows.length * (PLAZA_ROW_HEIGHT + PLAZA_ROW_GAP);
        var loopDuration = Math.max(
            sourceRows.length * PLAZA_SECONDS_PER_ROW,
            PLAZA_VISIBLE_ROWS * PLAZA_SECONDS_PER_ROW
        );

        // 一组数据末尾保留一个 row-gap，再紧接完全相同的第二组；轨道移动一整组高度后，第二组首行与初始首行位置一致，循环重置时不会闪白或跳帧。
        return [
            '<div class="plaza-carousel-viewport">',
            '<div class="plaza-carousel-track',
            shouldLoop ? ' is-looping' : '',
            '" style="--plaza-loop-distance:',
            loopDistance,
            'px;--plaza-loop-duration:',
            loopDuration,
            's">',
            '<div class="plaza-carousel-set">',
            rowHTML,
            '</div>',
            shouldLoop
                ? '<div class="plaza-carousel-set" aria-hidden="true">' +
                  rowHTML +
                  '</div>'
                : '',
            '</div>',
            '</div>',
        ].join('');
    }

    function renderPlaza() {
        var plazaRows = activityData.plazaRows || [];
        var previousRows = activityData.previousRows || [];
        var firstBody = [
            '<h2 class="panel-title">',
            t(
                'cp.plazaGiftTitle',
                'CP formation gifts worth more than 5,000 coins are shown here'
            ),
            '</h2>',
            renderPlazaCarousel(plazaRows),
        ].join('');
        var panels = [renderPanel('plaza-panel-a', 1816, 1152, firstBody)];
        if (previousRows.length) {
            var secondBody = [
                '<h2 class="panel-title">',
                t('cp.previousNo1Title', 'Previous Top 3'),
                '</h2>',
                '<div class="cp-list">',
                previousRows.map(renderCPRow).join(''),
                '</div>',
            ].join('');
            panels.push(renderPanel('plaza-panel-b', 3024, 1126, secondBody));
        }

        return panels.join('');
    }

    function renderInlineCountdown() {
        var units = [
            ['days', 'cp.days', 'D'],
            ['hours', 'cp.hours', 'H'],
            ['minutes', 'cp.minutes', 'M'],
            ['seconds', 'cp.seconds', 'S'],
        ];
        return [
            '<div class="countdown-inline">',
            units
                .map(function (unit) {
                    return [
                        '<div class="time-unit">',
                        '<img src="./assets/countdown-heart.png" alt="" aria-hidden="true" />',
                        '<strong data-count="',
                        unit[0],
                        '">02</strong>',
                        '<span>',
                        t(unit[1], unit[2]),
                        '</span>',
                        '</div>',
                    ].join('');
                })
                .join(''),
            '</div>',
        ].join('');
    }

    function renderPodiumCard(item) {
        var crown =
            item.place === 1
                ? 'rank-crown-gold.png'
                : item.place === 2
                  ? 'rank-crown-silver.png'
                  : 'crown-bronze.png';
        return [
            '<article class="podium-card rank-',
            item.place,
            '">',
            '<img class="podium-bg" src="./assets/rank-wing-heart.png" alt="" aria-hidden="true" />',
            '<img class="podium-crown" src="./assets/',
            crown,
            '" alt="" aria-hidden="true" />',
            renderAvatar('podium-avatar left', item.leftAvatar),
            renderAvatar('podium-avatar right', item.rightAvatar),
            '<div class="podium-names"><span>',
            escapeHTML(item.leftName),
            '</span><span>',
            escapeHTML(item.rightName),
            '</span></div>',
            '</article>',
        ].join('');
    }

    function renderRankRow(item) {
        return renderCPRow({
            type: 'score',
            leftName: item.leftName,
            rightName: item.rightName,
            leftAvatar: item.leftAvatar,
            rightAvatar: item.rightAvatar,
            score: item.score,
        });
    }

    function renderRank() {
        var rankRows = activityData.rank || [];
        var podium = [
            '<section class="rank-podium">',
            rankRows.slice(0, 3).map(renderPodiumCard).join(''),
            '</section>',
        ].join('');
        var panelBody = [
            renderInlineCountdown(),
            '<div class="cp-list">',
            rankRows.map(renderRankRow).join(''),
            '</div>',
        ].join('');
        return podium + renderPanel('rank-panel', 2430, 1107, panelBody);
    }

    function renderRewardItem(item) {
        var name = item.name || t(item.key, item.key);
        var note = item.note || (item.noteKey ? t(item.noteKey, '') : '');
        var cover = item.coverUrl || './assets/reward-frame.png';
        var cardClass =
            item.resourceType === 'coin'
                ? 'reward-card is-coin'
                : 'reward-card';
        return [
            '<article class="',
            cardClass,
            '">',
            '<div class="reward-icon-box"><img src="',
            escapeHTML(cover),
            '" alt="" aria-hidden="true" /></div>',
            '<div class="reward-name">',
            escapeHTML(name),
            '</div>',
            note
                ? '<div class="reward-note">' + escapeHTML(note) + '</div>'
                : '',
            '</article>',
        ].join('');
    }

    function renderRewardPanel(section, index) {
        var className = [
            'reward-panel',
            'reward-' + ['a', 'b', 'c'][index],
        ].join(' ');
        var top = REWARD_FIRST_TOP;
        for (var cursor = 0; cursor < index; cursor += 1) {
            top +=
                estimateRewardPanelHeight(
                    (activityData.rewards || mockData.rewards)[cursor]
                ) + REWARD_PANEL_GAP;
        }
        var height = estimateRewardPanelHeight(section);
        var body = [
            '<img class="reward-crown" src="./assets/',
            section.crown,
            '" alt="" aria-hidden="true" />',
            '<div class="reward-grid">',
            section.items.map(renderRewardItem).join(''),
            '</div>',
        ].join('');
        return renderPanel(className, top, height, body);
    }

    function renderRewards() {
        var sections = activityData.rewards || mockData.rewards;
        var bottom = REWARD_FIRST_TOP;
        var html = sections
            .map(function (section, index) {
                var panel = renderRewardPanel(section, index);
                bottom += estimateRewardPanelHeight(section) + REWARD_PANEL_GAP;
                return panel;
            })
            .join('');
        rewardStageHeight =
            bottom - REWARD_PANEL_GAP + REWARD_STAGE_BOTTOM_PADDING;
        return html;
    }

    function syncRewardPanelLayout() {
        if (activeTab !== 'rewards') return;
        var nextTop = REWARD_FIRST_TOP;
        var panels = Array.prototype.slice.call(
            tabContent.querySelectorAll('.reward-panel')
        );
        panels.forEach(function (panel) {
            var grid = panel.querySelector('.reward-grid');
            var measuredHeight = REWARD_MIN_PANEL_HEIGHT;
            // 奖励内容来自接口，不同档位数量和多语言换行都可能变化；渲染后用真实 grid 高度回写面板高度，避免固定 912px 留出大空白。
            if (grid) {
                measuredHeight = Math.max(
                    measuredHeight,
                    grid.offsetTop +
                        grid.offsetHeight +
                        REWARD_PANEL_BOTTOM_PADDING
                );
            }
            measuredHeight = Math.ceil(measuredHeight);
            panel.style.top = nextTop + 'px';
            panel.style.height = measuredHeight + 'px';
            nextTop += measuredHeight + REWARD_PANEL_GAP;
        });
        if (panels.length) {
            rewardStageHeight =
                nextTop - REWARD_PANEL_GAP + REWARD_STAGE_BOTTOM_PADDING;
        }
    }

    function formatScore(value) {
        var number = Number(value || 0);
        if (!Number.isFinite(number)) return '0';
        return number.toLocaleString('en-US');
    }

    function normalizeUser(user) {
        return user || {};
    }

    function normalizePairUser(user) {
        var source = normalizeUser(user);
        var userID = source.user_id || source.userId || '';
        var displayID = source.display_user_id || source.displayUserId || '';
        var name = source.username || source.name || displayID || userID || '';
        if (!name && !source.avatar) return null;
        return {
            name: name,
            avatar: source.avatar || '',
        };
    }

    function normalizeRankEntry(entry) {
        var userA = normalizePairUser(entry.user_a);
        var userB = normalizePairUser(entry.user_b);
        if (!userA || !userB) return null;
        return {
            type: 'score',
            place: Number(entry.rank || 0),
            score: formatScore(entry.score),
            leftName: userA.name,
            rightName: userB.name,
            leftAvatar: userA.avatar,
            rightAvatar: userB.avatar,
        };
    }

    function normalizeFormationGiftEntry(entry) {
        var giftCoinValue = Number(
            (entry &&
                (entry.gift_coin_value ||
                    entry.giftCoinValue ||
                    entry.coin_spent ||
                    entry.coinSpent)) ||
                0
        );
        var requester = normalizePairUser(
            entry && (entry.requester || entry.user_a || entry.userA)
        );
        var target = normalizePairUser(
            entry && (entry.target || entry.user_b || entry.userB)
        );
        // 业务定义是“超过 5000 金币”，不是大于等于；即使旧网关误返回 5000 或更低的记录，H5 也不能把它展示出来。
        if (
            !Number.isFinite(giftCoinValue) ||
            giftCoinValue <= 5000 ||
            !requester ||
            !target
        )
            return null;
        return {
            type: 'score',
            rawGiftCoinValue: giftCoinValue,
            score: formatScore(giftCoinValue),
            leftName: requester.name,
            rightName: target.name,
            leftAvatar: requester.avatar,
            rightAvatar: target.avatar,
        };
    }

    function rewardName(item) {
        var type = item.resource_type || 'reward';
        if (item.duration_days > 0)
            return type + ' ' + item.duration_days + 'D';
        if (item.quantity > 0) return type + ' x' + item.quantity;
        return type;
    }

    function rewardResourceType(item) {
        return String(
            item.resource_type || item.resourceType || ''
        ).toLowerCase();
    }

    function rewardCoverUrl(item) {
        var resourceType = rewardResourceType(item);
        if (resourceType === 'coin') return LALU_COIN_IMAGE;
        return item.cover_url || item.coverUrl || '';
    }

    function normalizeRewardSection(reward, index) {
        var crowns = ['crown-gold.png', 'crown-silver.png', 'crown-bronze.png'];
        return {
            crown: crowns[index] || 'crown-bronze.png',
            items: (reward.items || []).map(function (item) {
                var resourceType = rewardResourceType(item);
                return {
                    name: rewardName(item),
                    resourceType: resourceType,
                    note:
                        item.duration_days > 0
                            ? item.duration_days + ' days'
                            : item.quantity > 0
                              ? 'x' + item.quantity
                              : '',
                    coverUrl: rewardCoverUrl(item),
                };
            }),
        };
    }

    function applyActivityStatus(status) {
        if (!status) return;
        if (status.period && status.period.end_ms > Date.now()) {
            activityData.periodEndMS = status.period.end_ms;
            countdownEndAt = status.period.end_ms;
        }
        if (Array.isArray(status.entries)) {
            var rankRows = status.entries
                .map(normalizeRankEntry)
                .filter(function (item) {
                    return Boolean(item);
                });
            activityData.rank = rankRows;
        }
        if (Array.isArray(status.previous_entries)) {
            activityData.previousRows = status.previous_entries
                .map(normalizeRankEntry)
                .filter(function (item) {
                    return Boolean(item);
                })
                .slice(0, 3);
        }
        if (Array.isArray(status.rewards) && status.rewards.length) {
            activityData.rewards = status.rewards.map(normalizeRewardSection);
        }
    }

    function applyPlazaFormationGiftFeed(data) {
        var items = data && Array.isArray(data.items) ? data.items : [];
        // feed 由后端按 CP 成立时间倒序返回；H5 只做口径校验并保留返回顺序，不再按金币额排成另一个榜单。
        activityData.plazaRows = items
            .map(normalizeFormationGiftEntry)
            .filter(function (item) {
                return Boolean(item);
            });
    }

    function loadActivityStatus() {
        if (!window.HyAppAPI || !window.HyAppAPI.cpWeeklyRank) return;
        // 周榜配置和奖励由后端控制；H5 只在接口成功时替换展示数据，失败保持静态兜底，避免活动页因为鉴权或网络问题白屏。
        window.HyAppAPI.cpWeeklyRank
            .status({ limit: 10 })
            .then(function (status) {
                applyActivityStatus(status);
                render();
            })
            .catch(function () {});
    }

    function loadPlazaFormationGiftFeed() {
        if (
            !window.HyAppAPI ||
            !window.HyAppAPI.cpSpace ||
            !window.HyAppAPI.cpSpace.formationGiftFeed
        ) {
            return;
        }
        // 20 条可让四行视窗持续轮播，同时限制头像 DOM 和图片解码数量；gateway/user-service 还会再次夹紧上限，避免参数被篡改后无界拉取。
        window.HyAppAPI.cpSpace
            .formationGiftFeed({ limit: PLAZA_FEED_LIMIT })
            .then(function (data) {
                applyPlazaFormationGiftFeed(data);
                render();
            })
            .catch(function () {});
    }

    function render() {
        document.title = t('cp.pageTitle', 'Last Weekly CP');
        tabContent.innerHTML =
            activeTab === 'rank'
                ? renderRank()
                : activeTab === 'rewards'
                  ? renderRewards()
                  : renderPlaza();
        applyTabState();
        syncRewardPanelLayout();
        updateStageHeight();
        updateCountdown();
    }

    function applyTabState() {
        tabs.forEach(function (tab) {
            var isActive = tab.getAttribute('data-tab') === activeTab;
            tab.classList.toggle('is-active', isActive);
            tab.querySelector('img').src = isActive
                ? './assets/tab-active.png'
                : './assets/tab-inactive.png';
        });
        page.setAttribute('data-tab', activeTab);
    }

    function getPageWidth() {
        var viewportWidth =
            window.innerWidth ||
            document.documentElement.clientWidth ||
            DESIGN_WIDTH;
        return Math.min(Math.max(viewportWidth, 1), MAX_PAGE_WIDTH);
    }

    function updateStageHeight() {
        var designHeight =
            activeTab === 'rewards'
                ? rewardStageHeight
                : stageHeights[activeTab] || stageHeights.plaza;
        var pageWidth = getPageWidth();
        var designScale = pageWidth / DESIGN_WIDTH;
        stage.style.minHeight = designHeight + 'px';
        stage.style.height = designHeight + 'px';
        // 页面保持 1080 设计稿坐标系，大屏只放大到 768px，避免桌面或平板 WebView 把活动页拉得过宽。
        document.documentElement.style.setProperty(
            '--page-width',
            pageWidth + 'px'
        );
        document.documentElement.style.setProperty(
            '--design-scale',
            String(designScale)
        );
        stageWrap.style.height = Math.ceil(designHeight * designScale) + 'px';
        copyright.style.top = designHeight - 77 + 'px';
        document.body.style.minHeight = stageWrap.style.height;
        viewport.style.minHeight = stageWrap.style.height;
        page.style.minHeight = stageWrap.style.height;
    }

    function bindTabs() {
        tabs.forEach(function (tab) {
            tab.addEventListener('click', function () {
                activeTab = tab.getAttribute('data-tab') || 'plaza';
                render();
            });
        });
    }

    function init() {
        countdownEndAt = resolveFallbackEndAt();
        bindTabs();
        render();
        loadPlazaFormationGiftFeed();
        loadActivityStatus();
        countdownTimer = window.setInterval(updateCountdown, 1000);
        window.addEventListener('resize', updateStageHeight);
        window.addEventListener('hyapp:i18n-ready', render);
    }

    window.addEventListener('beforeunload', function () {
        if (countdownTimer) window.clearInterval(countdownTimer);
    });

    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', init);
    } else {
        init();
    }
})();
