(function () {
    var INVITE_CODE_KEYS = [
        'invite_code',
        'inviteCode',
        'code',
        'invitationCode',
    ];
    var SHARE_NAME_KEYS = ['name', 'nickname', 'inviterName', 'userName'];
    var SHARE_AVATAR_KEYS = ['avatar', 'avatarUrl', 'avatar_url', 'headUrl'];
    var PASS_THROUGH_KEYS = [
        'env',
        'app_code',
        'appCode',
        'lang',
        'downloadUrl',
        'download_url',
        'androidUrl',
        'android_url',
        'iosUrl',
        'ios_url',
        'url',
    ];
    var BIND_INVITE_VISIBLE_WINDOW_MS = 48 * 60 * 60 * 1000;
    var params = new URLSearchParams(window.location.search);
    var state = {
        inviteCode: firstParam(INVITE_CODE_KEYS),
        inviterName: firstParam(SHARE_NAME_KEYS),
        inviterAvatar: firstParam(SHARE_AVATAR_KEYS),
        inviteLink: '',
        currentUser: null,
        currentUserCreatedAtMS: 0,
        currentUserTimingLoaded: false,
        serverTimeMS: 0,
        pendingInviteCode: '',
        searchedInviter: null,
        boundInviter: null,
        boundInviterLoaded: false,
        boundInviterLoading: null,
        inviteRewardStatus: null,
        rankRows: [],
        rankLoaded: false,
        rankLoading: false,
        searchingInviter: false,
        bindingInviter: false,
        viewingBoundInviter: false,
        claiming: {},
    };

    function $(selector) {
        return document.querySelector(selector);
    }

    function firstParam(keys) {
        for (var i = 0; i < keys.length; i += 1) {
            var value = String(params.get(keys[i]) || '').trim();
            if (value) return value;
        }
        return '';
    }

    function textValue(value) {
        return String(value || '').trim();
    }

    function normalizeInviteCodeInput(value) {
        return textValue(value).toUpperCase();
    }

    function readRawPath(source, path) {
        var value = source;
        for (var i = 0; i < path.length; i += 1) {
            if (!value || typeof value !== 'object') return '';
            value = value[path[i]];
        }
        return value;
    }

    function readPath(source, path) {
        var value = readRawPath(source, path);
        return textValue(value);
    }

    function firstPath(source, paths) {
        for (var i = 0; i < paths.length; i += 1) {
            var value = readPath(source, paths[i]);
            if (value) return value;
        }
        return '';
    }

    function normalizeTimestampMS(value) {
        if (value === undefined || value === null || value === '') return 0;
        if (typeof value === 'string' && !String(value).trim()) return 0;
        var number = Number(value);
        if (Number.isFinite(number) && number > 0) {
            return number < 100000000000 ? number * 1000 : number;
        }
        var parsed = Date.parse(value);
        return Number.isFinite(parsed) && parsed > 0 ? parsed : 0;
    }

    function firstTimestampMS(source, paths) {
        for (var i = 0; i < paths.length; i += 1) {
            var value = normalizeTimestampMS(readRawPath(source, paths[i]));
            if (value) return value;
        }
        return 0;
    }

    function currentUserPayload(data, profile) {
        var target = profile || data || {};
        return Boolean(
            target.user_id ||
            target.userId ||
            target.display_user_id ||
            target.displayUserId ||
            target.username ||
            target.nickname ||
            target.created_at_ms !== undefined ||
            target.createdAtMs !== undefined ||
            target.profile_completed !== undefined ||
            target.profileCompleted !== undefined
        );
    }

    function mergeCurrentUser(profile) {
        if (!profile || typeof profile !== 'object') return;
        state.currentUser = Object.assign({}, state.currentUser || {}, profile);
    }

    function currentLandingURL() {
        return new URL('../invite-landing/', window.location.href);
    }

    function setInviteCodeParams(searchParams, inviteCode) {
        searchParams.set('invite_code', inviteCode);
        searchParams.set('inviteCode', inviteCode);
        searchParams.set('code', inviteCode);
    }

    function buildInviteLink() {
        var code = textValue(state.inviteCode);
        if (!code) return '';

        var url = currentLandingURL();
        PASS_THROUGH_KEYS.forEach(function (key) {
            var value = textValue(params.get(key));
            if (value) url.searchParams.set(key, value);
        });
        setInviteCodeParams(url.searchParams, code);
        if (state.inviterName) {
            url.searchParams.set('name', state.inviterName);
            url.searchParams.set('nickname', state.inviterName);
        }
        if (state.inviterAvatar) {
            url.searchParams.set('avatar', state.inviterAvatar);
            url.searchParams.set('avatar_url', state.inviterAvatar);
        }
        return url.toString();
    }

    function renderInviteShare() {
        state.inviteLink = buildInviteLink();
        var link = $('#inviteLink');
        var code = $('#inviteCode');
        if (link) link.textContent = state.inviteLink || '--';
        if (code) code.textContent = state.inviteCode || '--';
    }

    function readOverviewPayload(payload) {
        return payload && payload.user ? payload.user : payload;
    }

    function applyCurrentUserTiming(data, profile) {
        var serverTimeMS = firstTimestampMS(data, [
            ['server_time_ms'],
            ['serverTimeMS'],
            ['serverTimeMs'],
            ['server_time'],
            ['serverTime'],
        ]);
        var createdAtMS = firstTimestampMS(data, [
            ['profile', 'created_at_ms'],
            ['profile', 'createdAtMs'],
            ['profile', 'created_at'],
            ['profile', 'createdAt'],
            ['profile', 'registered_at_ms'],
            ['profile', 'registeredAtMs'],
            ['profile', 'registered_at'],
            ['profile', 'registeredAt'],
            ['created_at_ms'],
            ['createdAtMs'],
            ['created_at'],
            ['createdAt'],
            ['registered_at_ms'],
            ['registeredAtMs'],
            ['registered_at'],
            ['registeredAt'],
        ]);
        if (!createdAtMS) {
            createdAtMS = firstTimestampMS(profile, [
                ['created_at_ms'],
                ['createdAtMs'],
                ['created_at'],
                ['createdAt'],
                ['registered_at_ms'],
                ['registeredAtMs'],
                ['registered_at'],
                ['registeredAt'],
            ]);
        }
        if (serverTimeMS) state.serverTimeMS = serverTimeMS;
        if (createdAtMS) state.currentUserCreatedAtMS = createdAtMS;
    }

    function bindInviteReferenceTimeMS() {
        return state.serverTimeMS || Date.now();
    }

    function canShowBindInviteButton() {
        var api = window.HyAppAPI || {};
        var hasToken = api.getAccessToken && api.getAccessToken();
        if (state.boundInviter) return true;
        if (hasToken && !state.currentUserTimingLoaded) return false;
        var current = state.currentUser || {};
        var createdAtMS =
            state.currentUserCreatedAtMS ||
            firstTimestampMS(current, [
                ['created_at_ms'],
                ['createdAtMs'],
                ['created_at'],
                ['createdAt'],
                ['registered_at_ms'],
                ['registeredAtMs'],
                ['registered_at'],
                ['registeredAt'],
            ]);
        if (!createdAtMS) return true;
        // 48 小时窗口必须用服务端返回的当前时间优先判断；接口缺少时间时才退回本机时间，避免用户手动改系统时间影响显隐。
        return (
            bindInviteReferenceTimeMS() - createdAtMS <=
            BIND_INVITE_VISIBLE_WINDOW_MS
        );
    }

    function renderBindInviteVisibility() {
        var button = $('#bindInviteButton');
        if (!button) return;
        var visible = canShowBindInviteButton();
        button.hidden = !visible;
        button.disabled = !visible;
        if (visible || !$('#bindInviteModal') || $('#bindInviteModal').hidden) {
            return;
        }
        closeBindModal();
    }

    function applyCurrentUser(payload) {
        var data = readOverviewPayload(payload || {});
        var profile = data.profile || data;
        applyCurrentUserTiming(data, profile);
        if (currentUserPayload(data, profile)) {
            state.currentUserTimingLoaded = true;
            mergeCurrentUser(profile);
        }
        var inviteCode = firstPath(data, [
            ['invite', 'my_invite_code'],
            ['invite', 'myInviteCode'],
            ['profile', 'invite', 'my_invite_code'],
            ['profile', 'invite', 'myInviteCode'],
            ['my_invite_code'],
            ['myInviteCode'],
            ['invite_code'],
            ['inviteCode'],
        ]);
        var name = firstPath(data, [
            ['profile', 'username'],
            ['profile', 'nickname'],
            ['username'],
            ['nickname'],
        ]);
        var avatar = firstPath(data, [
            ['profile', 'avatar'],
            ['profile', 'avatar_url'],
            ['avatar'],
            ['avatar_url'],
        ]);

        if (inviteCode) state.inviteCode = inviteCode;
        if (name) state.inviterName = name;
        if (avatar) state.inviterAvatar = avatar;

        var inviteOverview = data.invite || profile.invite || {};
        var inviteCount = inviteOverview.invite_count;
        var validInviteCount = inviteOverview.valid_invite_count;
        if (
            inviteCount !== undefined &&
            inviteCount !== null &&
            $('#statInvitees')
        ) {
            $('#statInvitees').textContent = inviteCount;
        }
        if (
            validInviteCount !== undefined &&
            validInviteCount !== null &&
            $('#statEligible')
        ) {
            $('#statEligible').textContent = validInviteCount;
        }
        renderInviteShare();
        renderBindInviteVisibility();
    }

    function applyBoundInviteReferrer(payload) {
        var invite = payload && (payload.invite || payload.Invite);
        var inviter = normalizeInviter(payload, '');
        if (!inviter) {
            state.boundInviter = null;
            renderBindInviteVisibility();
            return;
        }
        inviter.inviteCode =
            textValue(
                firstObjectValue(invite, [
                    'invite_code',
                    'inviteCode',
                    'my_invite_code',
                    'myInviteCode',
                ])
            ) || inviter.inviteCode;
        state.boundInviter = inviter;
        state.searchedInviter = inviter;
        renderBindInviteVisibility();
    }

    function loadBoundInviteReferrer() {
        var api = window.HyAppAPI && window.HyAppAPI.user;
        var rootAPI = window.HyAppAPI || {};
        if (state.boundInviterLoading) return state.boundInviterLoading;
        if (
            !api ||
            !api.getInviteReferrer ||
            !rootAPI.getAccessToken ||
            !rootAPI.getAccessToken()
        ) {
            state.boundInviterLoaded = true;
            return Promise.resolve();
        }
        // 已绑定关系必须每次从服务端读取；本地只缓存展示结果，避免刷新后重新进入搜索绑定流程。
        state.boundInviterLoading = api
            .getInviteReferrer()
            .then(applyBoundInviteReferrer)
            .catch(function () {})
            .then(function () {
                state.boundInviterLoaded = true;
                state.boundInviterLoading = null;
            });
        return state.boundInviterLoading;
    }

    function loadCurrentUser() {
        var api = window.HyAppAPI || {};
        var userAPI = api.user || api.users;
        var hasToken = api.getAccessToken && api.getAccessToken();
        var userPromise = Promise.resolve();
        if (hasToken && api.get) {
            userPromise = window.HyAppAPI.get(
                '/api/v1/users/me/invite-overview'
            )
                .then(applyCurrentUser)
                .catch(function () {});
        }
        function loadMeProfile() {
            if (!hasToken || !userAPI || !userAPI.me) return Promise.resolve();
            return userAPI
                .me()
                .then(applyCurrentUser)
                .catch(function () {});
        }

        if (window.HyAppParams && window.HyAppParams.loadUser) {
            return userPromise
                .then(function () {
                    return window.HyAppParams.loadUser();
                })
                .then(function (current) {
                    if (current && current.user) applyCurrentUser(current.user);
                })
                .then(loadMeProfile);
        }
        if (userAPI) {
            if (userAPI.overview) {
                return userPromise
                    .then(function () {
                        return userAPI.overview();
                    })
                    .then(applyCurrentUser)
                    .then(loadMeProfile);
            }
            if (userAPI.me) {
                return userPromise.then(loadMeProfile);
            }
        }
        return userPromise.then(loadMeProfile);
    }

    function toast(message) {
        if (window.HyToast && window.HyToast.show) {
            window.HyToast.show(message);
            return;
        }
        window.alert(message);
    }

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

    function formatPeople(value) {
        return t('invite.peopleSuffix', '{value} people').replace(
            '{value}',
            value
        );
    }

    function formatNumber(value) {
        return new Intl.NumberFormat(
            window.HyAppI18n && window.HyAppI18n.lang
                ? window.HyAppI18n.lang()
                : 'en'
        ).format(Number(value || 0));
    }

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

    function field(source, snakeKey, camelKey) {
        if (!source || typeof source !== 'object') return undefined;
        if (Object.prototype.hasOwnProperty.call(source, snakeKey)) {
            return source[snakeKey];
        }
        if (
            camelKey &&
            Object.prototype.hasOwnProperty.call(source, camelKey)
        ) {
            return source[camelKey];
        }
        return undefined;
    }

    function setText(selector, value) {
        var node = $(selector);
        if (node) node.textContent = value;
    }

    function normalizeRankPayload(payload) {
        if (!payload || typeof payload !== 'object') return [];
        var items = field(payload, 'entries', 'entries');
        if (!Array.isArray(items)) items = field(payload, 'items', 'items');
        if (!Array.isArray(items)) return [];
        return items
            .map(function (item, index) {
                var user = field(item, 'user', 'user') || {};
                var userID = textValue(field(item, 'user_id', 'userId'));
                return {
                    rank:
                        numberValue(field(item, 'rank_no', 'rankNo')) ||
                        index + 1,
                    name:
                        textValue(field(user, 'username', 'username')) ||
                        textValue(
                            field(user, 'display_user_id', 'displayUserId')
                        ) ||
                        (userID ? 'ID ' + userID : '--'),
                    avatar: textValue(field(user, 'avatar', 'avatar')),
                    score: numberValue(
                        field(item, 'valid_invite_count', 'validInviteCount')
                    ),
                };
            })
            .filter(function (item) {
                return item.rank > 0 && item.score > 0;
            });
    }

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

    function updateCountdown() {
        var now = Date.now();
        var end = new Date();
        end.setDate(end.getDate() + 1);
        end.setHours(0, 0, 0, 0);
        var diff = Math.max(0, end.getTime() - 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;
        $('#days').textContent = pad(days);
        $('#hours').textContent = pad(hours);
        $('#minutes').textContent = pad(minutes);
        $('#seconds').textContent = pad(seconds);
    }

    function renderRank() {
        var list = $('#rankList');
        if (!list) return;
        list.textContent = '';
        if (state.rankLoading && !state.rankRows.length) {
            list.appendChild(
                emptyTaskNode(t('invite.rankLoading', 'Loading rank...'))
            );
            return;
        }
        if (!state.rankRows.length) {
            list.appendChild(
                emptyTaskNode(t('invite.noRankData', 'No rank data'))
            );
            return;
        }
        state.rankRows.forEach(function (item) {
            var row = document.createElement('article');
            var rank = document.createElement('span');
            var medal = document.createElement('img');
            var avatar = document.createElement('img');
            var name = document.createElement('strong');
            var score = document.createElement('span');

            row.className = 'rank-row';
            rank.className = 'rank-no';
            medal.className = 'rank-medal';
            avatar.className = 'rank-avatar';
            name.className = 'rank-name';
            score.className = 'rank-score';

            if (item.rank <= 3) {
                medal.src = './assets/medal-' + item.rank + '.png';
                medal.alt = 'Rank ' + item.rank;
                rank.textContent = '';
            } else {
                medal.alt = '';
                rank.textContent = item.rank;
            }

            avatar.src = item.avatar || './assets/rank-avatar.webp';
            avatar.onerror = function () {
                avatar.onerror = null;
                avatar.src = './assets/rank-avatar.webp';
            };
            avatar.alt = '';
            name.textContent = item.name;
            score.textContent = formatPeople(formatNumber(item.score));

            row.appendChild(rank);
            row.appendChild(
                item.rank <= 3 ? medal : document.createElement('span')
            );
            row.appendChild(avatar);
            row.appendChild(name);
            row.appendChild(score);
            list.appendChild(row);
        });
    }

    function normalizeInviteRewardStatus(payload) {
        if (!payload || typeof payload !== 'object') return null;
        return payload.status && typeof payload.status === 'object'
            ? payload.status
            : payload;
    }

    function claimKey(rewardType, tierID) {
        return rewardType + ':' + tierID;
    }

    function tierID(tier) {
        return numberValue(field(tier, 'tier_id', 'tierId'));
    }

    function tierRewardType(tier) {
        return String(field(tier, 'reward_type', 'rewardType') || '');
    }

    function tierName(tier, index, rewardType) {
        return (
            textValue(field(tier, 'tier_name', 'tierName')) ||
            textValue(field(tier, 'tier_code', 'tierCode')) ||
            (rewardType === 'recharge'
                ? t('invite.rechargeMilestone', 'Recharge milestone {index}')
                : t(
                      'invite.validInviteMilestone',
                      'Invitation milestone {index}'
                  )
            ).replace('{index}', index + 1)
        );
    }

    function thresholdValue(tier, rewardType) {
        return rewardType === 'valid_invite'
            ? numberValue(
                  field(
                      tier,
                      'threshold_valid_invite_count',
                      'thresholdValidInviteCount'
                  )
              )
            : numberValue(
                  field(tier, 'threshold_coin_amount', 'thresholdCoinAmount')
              );
    }

    function rewardCoinAmount(tier) {
        return numberValue(
            field(tier, 'reward_coin_amount', 'rewardCoinAmount')
        );
    }

    function tierClaimed(tier) {
        return Boolean(field(tier, 'claimed', 'claimed'));
    }

    function tierReached(tier) {
        return Boolean(field(tier, 'reached', 'reached'));
    }

    function tierClaimable(tier, status) {
        var rewardType = tierRewardType(tier);
        var progress = (status && field(status, 'progress', 'progress')) || {};
        if (
            !Boolean(field(status || {}, 'enabled', 'enabled')) ||
            tierClaimed(tier)
        ) {
            return false;
        }
        if (rewardType === 'recharge') {
            return (
                tierID(tier) ===
                numberValue(
                    field(
                        progress,
                        'recharge_claimable_tier_id',
                        'rechargeClaimableTierId'
                    )
                )
            );
        }
        return Boolean(field(tier, 'claimable', 'claimable'));
    }

    function taskDescription(tier, rewardType) {
        var threshold = formatNumber(thresholdValue(tier, rewardType));
        var reward = formatNumber(rewardCoinAmount(tier));
        if (rewardType === 'valid_invite') {
            return t(
                'invite.validInviteTaskDescription',
                'Invite {threshold} valid friends, reward {reward} coins'
            )
                .replace('{threshold}', threshold)
                .replace('{reward}', reward);
        }
        return t(
            'invite.rechargeTaskDescription',
            'Invitees recharge {threshold} coins, reward {reward} coins'
        )
            .replace('{threshold}', threshold)
            .replace('{reward}', reward);
    }

    function emptyTaskNode(message) {
        var node = document.createElement('p');
        node.className = 'task-empty';
        node.textContent = message;
        return node;
    }

    function buildClaimButton(tier, status) {
        var rewardType = tierRewardType(tier);
        var id = tierID(tier);
        var key = claimKey(rewardType, id);
        var claimed = tierClaimed(tier);
        var ready = tierClaimable(tier, status);
        var button = document.createElement('button');
        button.className = 'claim-button';
        if (ready) button.classList.add('is-ready');
        button.type = 'button';
        button.disabled = !ready || Boolean(state.claiming[key]);
        button.textContent = state.claiming[key]
            ? t('invite.claiming', 'Claiming')
            : claimed
              ? t('invite.claimed', 'Claimed')
              : t('invite.claim', 'Claim');
        button.addEventListener('click', function () {
            claimInviteReward(tier);
        });
        return button;
    }

    function renderRewardTier(container, tier, index, status) {
        var rewardType = tierRewardType(tier);
        var article = document.createElement('article');
        var content = document.createElement('div');
        var title = document.createElement('h3');
        var desc = document.createElement('p');

        article.className =
            rewardType === 'recharge' ? 'milestone' : 'quota-card';
        article.classList.toggle('is-done', tierClaimed(tier));
        article.classList.toggle(
            'is-current',
            tierReached(tier) && !tierClaimed(tier)
        );
        title.textContent = tierName(tier, index, rewardType);
        desc.textContent = taskDescription(tier, rewardType);

        content.appendChild(title);
        content.appendChild(desc);
        article.appendChild(content);
        article.appendChild(buildClaimButton(tier, status));
        container.appendChild(article);
    }

    function renderTaskList(selector, status, rewardType) {
        var container = $(selector);
        if (!container) return;
        container.textContent = '';
        var tiers = ((status && field(status, 'tiers', 'tiers')) || [])
            .filter(function (tier) {
                return (
                    tierRewardType(tier) === rewardType &&
                    String(field(tier, 'status', 'status') || 'active') !==
                        'inactive'
                );
            })
            .sort(function (left, right) {
                var sortLeft = numberValue(
                    field(left, 'sort_order', 'sortOrder')
                );
                var sortRight = numberValue(
                    field(right, 'sort_order', 'sortOrder')
                );
                if (sortLeft === sortRight) {
                    return (
                        thresholdValue(left, rewardType) -
                        thresholdValue(right, rewardType)
                    );
                }
                return sortLeft - sortRight;
            });
        if (!tiers.length) {
            container.appendChild(
                emptyTaskNode(t('invite.noRewardTasks', 'No reward tasks'))
            );
            return;
        }
        tiers.forEach(function (tier, index) {
            renderRewardTier(container, tier, index, status);
        });
    }

    function grantedRewardTotal(status) {
        return ((status && field(status, 'claims', 'claims')) || []).reduce(
            function (total, claim) {
                if (
                    String(field(claim, 'status', 'status') || '') !== 'granted'
                ) {
                    return total;
                }
                return (
                    total +
                    numberValue(
                        field(claim, 'reward_coin_amount', 'rewardCoinAmount')
                    )
                );
            },
            0
        );
    }

    function renderInviteActivityReward(status) {
        state.inviteRewardStatus = normalizeInviteRewardStatus(status);
        var current = state.inviteRewardStatus || {};
        var progress = field(current, 'progress', 'progress') || {};
        var perInviteReward = numberValue(
            field(
                current,
                'per_invite_inviter_reward_coin_amount',
                'perInviteInviterRewardCoinAmount'
            )
        );

        if (perInviteReward > 0) {
            setText(
                '#rewardInviteAmount',
                '+' + formatNumber(perInviteReward) + '(Max40,000)'
            );
        }

        if (state.inviteRewardStatus) {
            setText(
                '#statTotalRecharged',
                formatNumber(
                    field(
                        progress,
                        'total_recharge_coin_amount',
                        'totalRechargeCoinAmount'
                    )
                )
            );
            setText(
                '#statEligible',
                formatNumber(
                    field(progress, 'valid_invite_count', 'validInviteCount')
                )
            );
            setText(
                '#statMyRewards',
                formatNumber(grantedRewardTotal(current))
            );
        }
        renderTaskList('#transportTimeline', current, 'recharge');
        renderTaskList('#quotaList', current, 'valid_invite');
    }

    function loadInviteActivityReward() {
        var api = window.HyAppAPI && window.HyAppAPI.inviteActivityReward;
        if (!api || !api.status || !window.HyAppAPI.getAccessToken()) {
            renderInviteActivityReward(null);
            return Promise.resolve();
        }
        return api
            .status()
            .then(function (status) {
                renderInviteActivityReward(status);
            })
            .catch(function () {
                renderInviteActivityReward(null);
            });
    }

    function loadInviteActivityLeaderboard(force) {
        var api = window.HyAppAPI && window.HyAppAPI.inviteActivityReward;
        if (
            state.rankLoading ||
            (state.rankLoaded && !force) ||
            !api ||
            !api.leaderboard ||
            !window.HyAppAPI.getAccessToken()
        ) {
            renderRank();
            return Promise.resolve();
        }
        state.rankLoading = true;
        renderRank();
        return api
            .leaderboard({ page: 1, page_size: 50 })
            .then(function (payload) {
                state.rankRows = normalizeRankPayload(payload);
                state.rankLoaded = true;
                state.rankLoading = false;
                renderRank();
            })
            .catch(function () {
                state.rankRows = [];
                state.rankLoaded = true;
                state.rankLoading = false;
                renderRank();
            });
    }

    function claimInviteReward(tier) {
        var api = window.HyAppAPI && window.HyAppAPI.inviteActivityReward;
        var rewardType = tierRewardType(tier);
        var id = tierID(tier);
        var key = claimKey(rewardType, id);
        if (!api || !api.claim || state.claiming[key]) return;
        if (!tierClaimable(tier, state.inviteRewardStatus)) {
            toast(t('invite.notAvailable', 'Not available yet'));
            return;
        }
        state.claiming[key] = true;
        renderInviteActivityReward(state.inviteRewardStatus);
        api.claim({
            reward_type: rewardType,
            tier_id: id,
            command_id:
                'invite_reward_' +
                rewardType +
                '_' +
                id +
                '_' +
                Date.now() +
                '_' +
                Math.random().toString(36).slice(2),
        })
            .then(function (payload) {
                delete state.claiming[key];
                renderInviteActivityReward(
                    normalizeInviteRewardStatus(payload && payload.status)
                );
                toast(t('invite.claimSuccess', 'Claimed'));
            })
            .catch(function (error) {
                delete state.claiming[key];
                renderInviteActivityReward(state.inviteRewardStatus);
                toast(
                    (error && error.message) ||
                        t('invite.claimFailed', 'Claim failed')
                );
            });
    }

    function setTab(tabName) {
        var monthly = $('#monthlyTask');
        var isQuota = tabName === 'quota';
        monthly.classList.toggle('is-quota', isQuota);

        document.querySelectorAll('.task-tab').forEach(function (button) {
            var active = button.getAttribute('data-tab') === tabName;
            button.classList.toggle('is-active', active);
            button.setAttribute('aria-selected', String(active));
        });

        $('#transportPane').classList.toggle('is-active', !isQuota);
        $('#quotaPane').classList.toggle('is-active', isQuota);
        $('#rankPanel').hidden = !isQuota;
        if (isQuota) loadInviteActivityLeaderboard(false);
    }

    function copyTextFrom(selector) {
        var node = $(selector);
        var text = node ? node.textContent.trim() : '';
        if (!text || text === '--') {
            toast(t('invite.copyFailed', 'Copy failed'));
            return;
        }
        function fallbackCopy() {
            var input = document.createElement('textarea');
            input.value = text;
            input.setAttribute('readonly', 'readonly');
            input.style.position = 'fixed';
            input.style.left = '-9999px';
            input.style.top = '0';
            document.body.appendChild(input);
            input.select();
            var ok = false;
            try {
                ok = document.execCommand('copy');
            } catch (error) {
                ok = false;
            }
            document.body.removeChild(input);
            toast(
                ok
                    ? t('invite.copied', 'Copied')
                    : t('invite.copyFailed', 'Copy failed')
            );
        }
        if (navigator.clipboard && navigator.clipboard.writeText) {
            navigator.clipboard
                .writeText(text)
                .then(function () {
                    toast(t('invite.copied', 'Copied'));
                })
                .catch(function () {
                    fallbackCopy();
                });
            return;
        }
        fallbackCopy();
    }

    function copyInviteLink() {
        copyTextFrom('#inviteLink');
    }

    function copyInviteCode() {
        copyTextFrom('#inviteCode');
    }

    function firstObjectValue(source, keys) {
        source = source || {};
        for (var i = 0; i < keys.length; i += 1) {
            var value = source[keys[i]];
            if (value !== undefined && value !== null && value !== '') {
                return value;
            }
        }
        return '';
    }

    function showBoundInviterModal() {
        if (state.boundInviter) {
            state.pendingInviteCode = '';
            state.searchedInviter = state.boundInviter;
            state.searchingInviter = false;
            state.bindingInviter = false;
            showBindResult(state.boundInviter, { bound: true });
            $('#bindInviteModal').hidden = false;
        }
    }

    function showBindSearchModal() {
        state.pendingInviteCode = '';
        state.searchedInviter = null;
        state.searchingInviter = false;
        state.bindingInviter = false;
        var input = $('#bindInviteInput');
        if (input) input.value = '';
        showBindInput();
        $('#bindInviteModal').hidden = false;
        window.setTimeout(function () {
            if (input) input.focus();
        }, 0);
    }

    function openBindModal() {
        if (!canShowBindInviteButton()) {
            renderBindInviteVisibility();
            return;
        }
        var api = window.HyAppAPI || {};
        if (!api.getAccessToken || !api.getAccessToken()) {
            toast(t('invite.loginRequired', 'Please log in first'));
            return;
        }
        if (state.boundInviter) {
            showBoundInviterModal();
            return;
        }
        if (!state.boundInviterLoaded) {
            loadBoundInviteReferrer().then(function () {
                if (state.boundInviter) {
                    showBoundInviterModal();
                    return;
                }
                showBindSearchModal();
            });
            return;
        }
        showBindSearchModal();
    }

    function closeBindModal() {
        $('#bindInviteModal').hidden = true;
        state.searchingInviter = false;
        state.bindingInviter = false;
        state.viewingBoundInviter = false;
        renderBindActions();
    }

    function showBindInput() {
        $('#bindInputCard').hidden = false;
        $('#bindResultCard').hidden = true;
        state.searchedInviter = null;
        state.viewingBoundInviter = false;
        renderBindActions();
    }

    function showBindResult(inviter, options) {
        var avatar = $('#inviterAvatar');
        var name = $('#inviterName');
        var displayID = $('#inviterDisplayId');
        if (avatar) {
            avatar.src = inviter.avatar || './assets/rank-avatar.webp';
            avatar.onerror = function () {
                avatar.onerror = null;
                avatar.src = './assets/rank-avatar.webp';
            };
        }
        if (name) name.textContent = inviter.name || '--';
        if (displayID) displayID.textContent = inviter.displayUserID || '--';
        $('#bindInputCard').hidden = true;
        $('#bindResultCard').hidden = false;
        state.viewingBoundInviter = Boolean(options && options.bound);
        renderBindActions();
    }

    function renderBindActions() {
        var cancel = $('#bindCancelButton');
        var confirm = $('#confirmBindButton');
        var input = $('#bindInviteInput');
        var busy = state.searchingInviter || state.bindingInviter;
        if (confirm) {
            confirm.hidden = state.viewingBoundInviter;
            confirm.disabled = state.viewingBoundInviter || busy;
            if (!state.viewingBoundInviter) {
                confirm.textContent = state.bindingInviter
                    ? t('invite.binding', 'Binding...')
                    : state.searchingInviter
                      ? t('invite.searchingInviter', 'Searching...')
                      : t('invite.confirm', 'Confirm');
            }
        }
        if (cancel) {
            cancel.disabled = busy;
            cancel.textContent = state.viewingBoundInviter
                ? t('invite.close', 'Close')
                : t('invite.cancel', 'Cancel');
        }
        if (input) input.disabled = busy;
    }

    function normalizeInviter(payload, fallbackDisplayUserID) {
        payload = payload || {};
        var wrapper = payload.inviter || payload.Inviter || payload;
        var identity = payload.identity || payload.Identity || payload;
        var profile =
            payload.profile ||
            payload.Profile ||
            wrapper.profile ||
            wrapper.Profile ||
            wrapper;
        var userID =
            textValue(firstObjectValue(profile, ['user_id', 'userId'])) ||
            textValue(firstObjectValue(identity, ['user_id', 'userId']));
        var displayUserID =
            textValue(
                firstObjectValue(profile, [
                    'pretty_display_user_id',
                    'prettyDisplayUserId',
                    'display_user_id',
                    'displayUserId',
                ])
            ) ||
            textValue(
                firstObjectValue(identity, [
                    'pretty_display_user_id',
                    'prettyDisplayUserId',
                    'display_user_id',
                    'displayUserId',
                ])
            ) ||
            fallbackDisplayUserID;
        var name =
            textValue(
                firstObjectValue(profile, ['username', 'nickname', 'name'])
            ) || displayUserID;
        var avatar = textValue(
            firstObjectValue(profile, ['avatar', 'avatar_url', 'avatarUrl'])
        );
        if (!userID && !displayUserID) return null;
        return {
            userID: userID,
            displayUserID: displayUserID,
            name: name,
            avatar: avatar,
        };
    }

    function isCurrentUser(inviter) {
        var current = state.currentUser || {};
        var currentUserID = textValue(
            firstObjectValue(current, ['user_id', 'userId'])
        );
        var currentDisplayID = textValue(
            firstObjectValue(current, [
                'pretty_display_user_id',
                'prettyDisplayUserId',
                'display_user_id',
                'displayUserId',
            ])
        );
        return Boolean(
            (currentUserID && currentUserID === inviter.userID) ||
            (currentDisplayID && currentDisplayID === inviter.displayUserID)
        );
    }

    function searchInviter() {
        if (state.searchingInviter) return;
        var input = $('#bindInviteInput');
        var inviteCode = normalizeInviteCodeInput(input && input.value);
        var api = window.HyAppAPI && window.HyAppAPI.user;
        if (input && input.value !== inviteCode) input.value = inviteCode;
        if (!inviteCode) {
            toast(
                t('invite.searchRequired', 'Please enter an invitation code')
            );
            return;
        }
        if (!api || !api.searchInviteReferrer) {
            toast(t('invite.bindFailed', 'Bind failed'));
            return;
        }
        state.searchingInviter = true;
        state.pendingInviteCode = inviteCode;
        renderBindActions();
        // 搜索入口只提交邀请码，由 server 解析归属并按当前用户国家过滤，前端不再用可被篡改的用户 ID 作为绑定入参。
        api.searchInviteReferrer(inviteCode)
            .then(function (payload) {
                var inviter = normalizeInviter(payload, '');
                state.searchingInviter = false;
                if (!inviter) {
                    renderBindActions();
                    toast(t('invite.inviterNotFound', 'Inviter not found'));
                    return;
                }
                if (isCurrentUser(inviter)) {
                    renderBindActions();
                    toast(
                        t(
                            'invite.cannotBindSelf',
                            'You cannot bind yourself as inviter'
                        )
                    );
                    return;
                }
                inviter.inviteCode = inviteCode;
                state.searchedInviter = inviter;
                showBindResult(inviter);
            })
            .catch(function (error) {
                state.searchingInviter = false;
                renderBindActions();
                toast(
                    (error && error.message) ||
                        t('invite.inviterNotFound', 'Inviter not found')
                );
            });
    }

    function confirmBindInviter() {
        if (state.viewingBoundInviter) {
            closeBindModal();
            return;
        }
        if (state.bindingInviter) return;
        var api = window.HyAppAPI && window.HyAppAPI.user;
        var inviter = state.searchedInviter;
        if (!inviter) {
            searchInviter();
            return;
        }
        if (!api || !api.bindInviteReferrer) {
            toast(t('invite.bindFailed', 'Bind failed'));
            return;
        }
        state.bindingInviter = true;
        renderBindActions();
        api.bindInviteReferrer(inviter.inviteCode || state.pendingInviteCode)
            .then(function (response) {
                var invite = response && response.invite;
                state.bindingInviter = false;
                renderBindActions();
                if (invite && (invite.bound || invite.invite_code)) {
                    var boundInviter = normalizeInviter(response, '') || inviter;
                    boundInviter.inviteCode =
                        textValue(
                            firstObjectValue(invite, [
                                'invite_code',
                                'inviteCode',
                            ])
                        ) ||
                        inviter.inviteCode ||
                        state.pendingInviteCode;
                    state.boundInviter = boundInviter;
                    state.boundInviterLoaded = true;
                    state.searchedInviter = boundInviter;
                    renderBindInviteVisibility();
                    toast(t('invite.bindSuccess', 'Bound successfully'));
                    closeBindModal();
                    loadCurrentUser().catch(function () {});
                    loadBoundInviteReferrer();
                    loadInviteActivityReward();
                    return;
                }
                toast(
                    t(
                        'invite.bindNoChange',
                        'Invite referrer is already bound.'
                    )
                );
            })
            .catch(function (error) {
                state.bindingInviter = false;
                renderBindActions();
                toast(
                    (error && error.message) ||
                        t('invite.bindFailed', 'Bind failed')
                );
            });
    }

    function bindEvents() {
        document.querySelectorAll('.task-tab').forEach(function (button) {
            button.addEventListener('click', function () {
                setTab(button.getAttribute('data-tab') || 'transport');
            });
        });
        $('#copyLinkButton').addEventListener('click', copyInviteLink);
        $('#copyCodeButton').addEventListener('click', copyInviteCode);
        $('#bindInviteButton').addEventListener('click', openBindModal);
        $('#bindCancelButton').addEventListener('click', closeBindModal);
        $('#confirmBindButton').addEventListener('click', confirmBindInviter);
        $('#bindInviteModal').addEventListener('click', function (event) {
            if (event.target === $('#bindInviteModal')) closeBindModal();
        });
        $('#bindInviteInput').addEventListener('keydown', function (event) {
            if (event.key === 'Enter') confirmBindInviter();
        });
        $('#bindInviteInput').addEventListener('input', function (event) {
            var nextValue = normalizeInviteCodeInput(event.target.value);
            if (event.target.value !== nextValue)
                event.target.value = nextValue;
        });
        document
            .querySelectorAll('.copy-task-button')
            .forEach(function (button) {
                button.addEventListener('click', copyInviteLink);
            });
    }

    function init() {
        renderInviteShare();
        renderRank();
        updateCountdown();
        setInterval(updateCountdown, 1000);
        renderBindInviteVisibility();
        bindEvents();
        renderInviteActivityReward(null);
        Promise.all([
            loadCurrentUser().catch(function () {
                renderInviteShare();
            }),
            loadBoundInviteReferrer(),
            loadInviteActivityReward(),
        ]);
    }

    window.addEventListener('hyapp:i18n-ready', function () {
        renderRank();
        renderBindActions();
        renderInviteActivityReward(state.inviteRewardStatus);
    });

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