(function () {
    var ASSET_BASE = './assets/recharge-activity/';
    var viewport = document.getElementById('appViewport');
    var page = document.getElementById('page');
    var stage = document.querySelector('.stage');
    var rewardSections = document.getElementById('rewardSections');
    var bgBottom = document.querySelector('.bg-bottom');
    var countNodes = {
        days: document.querySelector('[data-count="days"]'),
        hours: document.querySelector('[data-count="hours"]'),
        minutes: document.querySelector('[data-count="minutes"]'),
        seconds: document.querySelector('[data-count="seconds"]'),
    };

    var DESIGN_WIDTH = 1080;
    var VIEWPORT_WIDTH = 375;
    var MAX_PAGE_WIDTH = 430;
    var DEFAULT_DESIGN_HEIGHT = 3273;
    var designHeight = DEFAULT_DESIGN_HEIGHT;
    var countdownEndAt = resolveCountdownEndAt();
    var countdownTimer = 0;
    var state = {
        user: {
            name: '',
            id: '',
            avatar: ASSET_BASE + 'profile-avatar.webp',
            accumulatedRecharge: 0,
        },
        rewards: [],
        claiming: {},
        loading: true,
        error: '',
    };
    var fallbackCards = [
        {
            price: '$100',
            icon: ASSET_BASE + 'reward-icon.png',
            left: 111,
            top: 293,
        },
        {
            price: '$100',
            icon: ASSET_BASE + 'reward-icon.png',
            left: 560,
            top: 293,
        },
    ];

    function getParams() {
        return new URLSearchParams(window.location.search || '');
    }

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

    function escapeHTML(value) {
        return String(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 showToast(message) {
        if (window.HyAppToast && window.HyAppToast.show) {
            window.HyAppToast.show(message);
            return;
        }
        window.dispatchEvent(
            new CustomEvent('hyapp:toast', { detail: { message: message } })
        );
    }

    function numeric(value, fallback) {
        var number = Number(value);
        return Number.isFinite(number) ? number : fallback || 0;
    }

    function parseJSON(value) {
        if (!value || typeof value !== 'string') return null;
        try {
            return JSON.parse(value);
        } catch (_) {
            return null;
        }
    }

    function firstValue() {
        for (var i = 0; i < arguments.length; i += 1) {
            var value = arguments[i];
            if (value !== undefined && value !== null && value !== '')
                return value;
        }
        return '';
    }

    function formatUSD(value) {
        var amount = numeric(value, 0);
        return (
            '$' +
            amount.toLocaleString('en-US', {
                maximumFractionDigits: 2,
                minimumFractionDigits: amount % 1 === 0 ? 0 : 2,
            })
        );
    }

    function monthlyResetEndAt() {
        var now = new Date();
        return new Date(
            now.getFullYear(),
            now.getMonth() + 1,
            1,
            0,
            0,
            0,
            0
        ).getTime();
    }

    function activityTimeEndAt(activityTime) {
        var matches = String(activityTime || '').match(
            /(\d{1,2})\s*\/\s*(\d{1,2})\s*$/
        );
        if (!matches) return 0;

        var now = new Date();
        var day = Number(matches[1]);
        var month = Number(matches[2]);
        if (!Number.isFinite(day) || !Number.isFinite(month)) return 0;

        // 后端月累充返回的 activityTime 是 DD/MM - DD/MM，不带年份；结束日次日 00:00 就是月度清空点。
        var endAt = new Date(
            now.getFullYear(),
            month - 1,
            day + 1,
            0,
            0,
            0,
            0
        ).getTime();
        return Number.isFinite(endAt) && endAt > Date.now() ? endAt : 0;
    }

    function resolveCountdownEndAt(statusData) {
        var params = getParams();
        var explicitEnd = Date.parse(
            params.get('end_at') || params.get('endAt') || ''
        );
        if (Number.isFinite(explicitEnd) && explicitEnd > Date.now())
            return explicitEnd;

        var hours = Number(params.get('hours'));
        if (Number.isFinite(hours) && hours > 0)
            return Date.now() + hours * 60 * 60 * 1000;

        return (
            activityTimeEndAt(statusData && statusData.activityTime) ||
            monthlyResetEndAt()
        );
    }

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

    function updateScale() {
        var pageWidth = getPageWidth();
        var designScale = pageWidth / DESIGN_WIDTH;
        var scaledHeight = Math.ceil(designHeight * designScale);

        // 视觉稿仍以 1080 坐标布局，只把整张背景和内容按真实 WebView 宽度等比缩放，避免 412px 等机型露出页面两侧空白。
        document.documentElement.style.setProperty(
            '--page-width',
            pageWidth + 'px'
        );
        document.documentElement.style.setProperty(
            '--design-scale',
            String(designScale)
        );
        viewport.style.minHeight = scaledHeight + 'px';
        viewport.style.height = scaledHeight + 'px';
        page.style.minHeight = scaledHeight + 'px';
        page.style.height = scaledHeight + 'px';
        document.body.style.minHeight =
            Math.max(scaledHeight, window.innerHeight || 0) + 'px';
    }

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

        countNodes.days.textContent = twoDigits(days);
        countNodes.hours.textContent = twoDigits(hours);
        countNodes.minutes.textContent = twoDigits(minutes);
        countNodes.seconds.textContent = twoDigits(seconds);
    }

    function normalizeUser(profile, statusData) {
        profile = profile || {};
        var params = getParams();
        return {
            name: firstValue(
                profile.userNickname,
                profile.username,
                profile.name,
                params.get('name'),
                'Aslan'
            ),
            id: String(
                firstValue(
                    profile.specialId,
                    profile.displayUserId,
                    profile.display_user_id,
                    profile.account,
                    profile.id,
                    profile.userId,
                    params.get('uid'),
                    params.get('id'),
                    ''
                )
            ),
            avatar: firstValue(
                profile.userAvatar,
                profile.avatar,
                profile.headImg,
                profile.headImage,
                params.get('avatar'),
                ASSET_BASE + 'profile-avatar.webp'
            ),
            accumulatedRecharge: firstValue(
                statusData && statusData.monthlyRecharge,
                params.get('recharge'),
                0
            ),
        };
    }

    function rewardProps(resource) {
        var group =
            resource && resource.activityResource
                ? resource.activityResource.propsGroup || {}
                : {};
        return Array.isArray(group.activityRewardProps)
            ? group.activityRewardProps
            : [];
    }

    function rule(resource) {
        return resource && resource.activityResource
            ? resource.activityResource.rule || {}
            : {};
    }

    function thresholdAmount(resource) {
        var data = parseJSON(rule(resource).jsonData) || {};
        return numeric(data.quantity, 0);
    }

    function cardLayout(count, index) {
        if (count >= 4) {
            return (
                [
                    { left: 70.5, top: 278 },
                    { left: 292.5, top: 278 },
                    { left: 514.5, top: 278 },
                    { left: 736.5, top: 278 },
                ][index] || { left: 736.5, top: 278 }
            );
        }
        if (count === 3) {
            return (
                [
                    { left: 70.5, top: 278 },
                    { left: 339.5, top: 278 },
                    { left: 608.5, top: 278 },
                ][index] || { left: 608.5, top: 278 }
            );
        }
        return (
            [
                { left: 111, top: 293 },
                { left: 560, top: 293 },
            ][index] || { left: 560, top: 293 }
        );
    }

    function normalizeCard(item, threshold, count, index) {
        var pos = cardLayout(count, index);
        return {
            price:
                item && item.amount
                    ? formatUSD(item.amount)
                    : formatUSD(threshold),
            icon: (item && item.cover) || ASSET_BASE + 'reward-icon.png',
            left: pos.left,
            top: pos.top,
        };
    }

    function normalizeReward(resource, index) {
        var currentRule = rule(resource);
        var ruleId = String(currentRule.id || resource.ruleId || '');
        var threshold = thresholdAmount(resource);
        var props = rewardProps(resource).slice(0, 4);
        var receiveStatus = String(resource.receiveStatus || '').toUpperCase();
        var claimed = receiveStatus === 'RECEIVED';
        var claimable = receiveStatus === 'NOT_RECEIVED';
        var cardCount = props.length || fallbackCards.length;

        return {
            ruleId: ruleId,
            amount: formatUSD(threshold),
            top: 1776 + index * 690,
            background:
                index % 2 === 0
                    ? ASSET_BASE + 'reward-section-a.webp'
                    : ASSET_BASE + 'reward-section-b.webp',
            claim: {
                text: claimed
                    ? t('rechargeReward.claimed', 'Claimed')
                    : t('rechargeReward.claim', 'Claim'),
                claimable: claimable,
                claimed: claimed,
                loading: Boolean(state.claiming[ruleId]),
            },
            cards: props.length
                ? props.map(function (item, cardIndex) {
                      return normalizeCard(
                          item,
                          threshold,
                          cardCount,
                          cardIndex
                      );
                  })
                : fallbackCards.map(function (card) {
                      return Object.assign({}, card, {
                          price: formatUSD(threshold),
                      });
                  }),
        };
    }

    function normalizeRewards(statusData) {
        var resources =
            statusData && Array.isArray(statusData.activityResources)
                ? statusData.activityResources
                : [];
        return resources
            .map(function (item, index) {
                return normalizeReward(item, index);
            })
            .filter(function (item) {
                return item.ruleId;
            });
    }

    function renderProfile(user) {
        document.querySelector('[data-profile-avatar]').src =
            user.avatar || ASSET_BASE + 'profile-avatar.webp';
        document.querySelector('[data-profile-name]').textContent =
            user.name || 'Aslan';
        document.querySelector('[data-profile-id]').textContent =
            t('rechargeReward.idPrefix', 'ID:') + ' ' + (user.id || '-');
        document.querySelector('[data-profile-recharge]').textContent =
            t('rechargeReward.accumulatedRecharge', 'Accumulated Recharge:') +
            formatUSD(user.accumulatedRecharge || 0);
    }

    function renderRewardCard(card) {
        return [
            '<div class="reward-card" style="left:',
            card.left,
            'px;top:',
            card.top,
            'px">',
            '<img class="reward-frame" src="',
            ASSET_BASE,
            'reward-card-frame.webp',
            '" alt="" />',
            '<img class="reward-icon" src="',
            escapeHTML(card.icon),
            '" alt="" />',
            '<span class="reward-price">',
            escapeHTML(card.price),
            '</span>',
            '</div>',
        ].join('');
    }

    function renderClaimButton(section) {
        var claim = section.claim || {};
        var stateClass = claim.claimed
            ? ' is-claimed'
            : claim.claimable
              ? ' is-claimable'
              : ' is-disabled';
        var disabled = !claim.claimable || claim.claimed || claim.loading;
        return [
            '<button class="claim-button',
            stateClass,
            '" type="button" data-rule-id="',
            escapeHTML(section.ruleId),
            '"',
            disabled ? ' disabled' : '',
            '>',
            '<img class="claim-button-bg" src="',
            ASSET_BASE,
            'receive-button-bg.png" alt="" />',
            '<span>',
            escapeHTML(
                claim.loading
                    ? t('rechargeReward.claiming', 'Claiming...')
                    : claim.text || t('rechargeReward.claim', 'Claim')
            ),
            '</span>',
            '</button>',
        ].join('');
    }

    function renderRewards(rewards) {
        if (state.loading) {
            rewardSections.innerHTML =
                '<p class="reward-message">' +
                escapeHTML(t('rechargeReward.loading', 'Loading...')) +
                '</p>';
            return;
        }
        if (state.error) {
            rewardSections.innerHTML =
                '<p class="reward-message is-error">' +
                escapeHTML(state.error) +
                '</p>';
            return;
        }
        if (!rewards.length) {
            rewardSections.innerHTML =
                '<p class="reward-message">' +
                escapeHTML(t('rechargeReward.noRewards', 'No rewards yet')) +
                '</p>';
            return;
        }

        rewardSections.innerHTML = rewards
            .map(function (section) {
                var title = t(
                    'rechargeReward.rechargeTitle',
                    'Recharge {amount}'
                ).replace('{amount}', section.amount);
                return [
                    '<section class="reward-section" style="--section-top:',
                    section.top,
                    'px">',
                    '<img class="reward-section-bg" src="',
                    escapeHTML(section.background),
                    '" alt="" />',
                    '<div class="title-pill">',
                    '<span>',
                    escapeHTML(title),
                    '</span>',
                    '</div>',
                    section.cards
                        .map(function (card) {
                            return renderRewardCard(card);
                        })
                        .join(''),
                    renderClaimButton(section),
                    '</section>',
                ].join('');
            })
            .join('');
    }

    function updateDesignHeight() {
        var rewardCount = Math.max(state.rewards.length, 2);
        designHeight = Math.max(
            DEFAULT_DESIGN_HEIGHT,
            1776 + rewardCount * 690 + 120
        );
        stage.style.height = designHeight + 'px';
        if (bgBottom)
            bgBottom.style.top = Math.max(2695, designHeight - 578) + 'px';
        updateScale();
    }

    function renderPage() {
        document.title = t('rechargeReward.pageTitle', 'Recharge Reward');
        renderProfile(state.user);
        updateDesignHeight();
        renderRewards(state.rewards);
    }

    function mockData() {
        var params = getParams();
        var claimed = params.get('claimed') === '1';
        return Promise.resolve({
            profile: {
                userNickname: params.get('name') || 'Aslan',
                account: params.get('uid') || '12345678',
                userAvatar:
                    params.get('avatar') || ASSET_BASE + 'profile-avatar.webp',
            },
            status: {
                monthlyRecharge: numeric(params.get('recharge'), 5998),
                activityResources: [
                    {
                        receiveStatus: claimed ? 'RECEIVED' : 'NOT_RECEIVED',
                        activityResource: {
                            rule: {
                                id: '1000000000000000001',
                                jsonData: '{"quantity":100}',
                            },
                            propsGroup: { activityRewardProps: [] },
                        },
                    },
                    {
                        receiveStatus: 'INELIGIBLE',
                        activityResource: {
                            rule: {
                                id: '1000000000000000002',
                                jsonData: '{"quantity":200}',
                            },
                            propsGroup: { activityRewardProps: [] },
                        },
                    },
                ],
            },
        });
    }

    function loadRemoteData() {
        if (!window.AslanCommon) {
            return Promise.reject(new Error('Aslan bridge unavailable'));
        }
        return Promise.all([
            window.AslanCommon.user.profile().catch(function (error) {
                console.warn('Aslan profile failed', error);
                return null;
            }),
            window.AslanCommon.rechargeReward.status(),
        ]).then(function (result) {
            return { profile: result[0], status: result[1] };
        });
    }

    function loadData() {
        state.loading = true;
        state.error = '';
        renderPage();

        var params = getParams();
        var loader =
            params.get('mock') === '1' || params.get('mock') === 'true'
                ? mockData()
                : loadRemoteData();

        return loader
            .then(function (payload) {
                var statusData = payload.status || {};
                countdownEndAt = resolveCountdownEndAt(statusData);
                updateCountdown();
                state.user = normalizeUser(payload.profile, statusData);
                state.rewards = normalizeRewards(statusData);
                state.loading = false;
                state.error = '';
                renderPage();
            })
            .catch(function (error) {
                console.warn('Aslan recharge reward load failed', error);
                state.loading = false;
                state.error =
                    (error && error.message) ||
                    t('rechargeReward.loadFailed', 'Load failed');
                renderPage();
            });
    }

    function markClaimed(ruleId) {
        state.rewards = state.rewards.map(function (item) {
            if (item.ruleId !== ruleId) return item;
            item.claim.claimed = true;
            item.claim.claimable = false;
            item.claim.loading = false;
            item.claim.text = t('rechargeReward.claimed', 'Claimed');
            return item;
        });
    }

    function claimReward(ruleId) {
        if (!ruleId || state.claiming[ruleId] || !window.AslanCommon) return;
        state.claiming[ruleId] = true;
        renderPage();

        // 领取必须只提交后端规则 Long 的字符串形式，避免 JS Number 精度损失导致发错档位。
        window.AslanCommon.rechargeReward
            .claim(ruleId)
            .then(function () {
                delete state.claiming[ruleId];
                markClaimed(ruleId);
                renderPage();
                showToast(t('rechargeReward.claimSuccess', 'Claimed'));
                return loadData();
            })
            .catch(function (error) {
                delete state.claiming[ruleId];
                renderPage();
                showToast(
                    (error && error.message) ||
                        t('rechargeReward.claimFailed', 'Claim failed')
                );
            });
    }

    function bindEvents() {
        rewardSections.addEventListener('click', function (event) {
            var button = event.target.closest('[data-rule-id]');
            if (!button || button.disabled) return;
            claimReward(button.getAttribute('data-rule-id'));
        });
        window.addEventListener('resize', updateScale);
        window.addEventListener('orientationchange', updateScale);
        window.addEventListener('hyapp:i18n-ready', function () {
            renderPage();
        });
    }

    function init() {
        updateScale();
        updateCountdown();
        renderPage();
        bindEvents();
        loadData();

        if (countdownTimer) window.clearInterval(countdownTimer);
        countdownTimer = window.setInterval(updateCountdown, 1000);
    }

    init();
})();
