(function () {
    'use strict';

    var PROD_API_BASE = 'https://jvapi.haiyihy.com';
    var TEST_API_BASE = 'https://jvapi-test.haiyihy.com';
    var LOCAL_API_BASE = 'http://127.0.0.1:13000';
    var APP_CODE = 'yumi';
    var RELATION_TYPE_BY_TAB = {
        cp: 'CP',
        brother: 'BROTHER',
        sister: 'SISTERS',
    };
    var headers = {
        authorization: '',
        'req-app-intel':
            'version=1.0.0;build=1;model=H5;sysVersion=web;channel=Web',
        'req-client': 'H5',
        'req-imei': 'H5-STATIC',
        'req-lang': 'en',
        'req-sys-origin': 'origin=YUMI;originChild=YUMI',
        'req-version': 'V2',
        'req-zone': 'Asia/Shanghai',
    };
    var readyPromise = null;

    function currentParams() {
        var params = new URLSearchParams(window.location.search || '');
        var hash = window.location.hash || '';
        if (hash.indexOf('?') >= 0) {
            new URLSearchParams(hash.split('?').slice(1).join('?')).forEach(
                function (value, key) {
                    if (!params.has(key)) params.set(key, value);
                }
            );
        }
        return params;
    }

    function query(name) {
        return currentParams().get(name);
    }

    function normalizeBaseURL(value) {
        return String(value || '').replace(/\/+$/, '');
    }

    function resolveEnv() {
        var env = String(query('env') || '')
            .trim()
            .toLowerCase();
        return env === 'test' || env === 'local' || env === 'dev' ? env : '';
    }

    function baseURL() {
        var config = window.YumiCommonConfig || {};
        var override =
            query('apiBase') ||
            query('api_base') ||
            query('yumi_api_base') ||
            window.YUMI_API_BASE_URL ||
            config.apiBase;
        if (override) return normalizeBaseURL(override);
        var env = resolveEnv();
        if (env === 'local')
            return normalizeBaseURL(config.localApi || LOCAL_API_BASE);
        if (env === 'test' || env === 'dev')
            return normalizeBaseURL(config.testApi || TEST_API_BASE);
        return normalizeBaseURL(config.prodApi || PROD_API_BASE);
    }

    function buildURL(path, queryData) {
        var url = new URL(
            String(path || '').replace(/^\/+/, ''),
            baseURL() + '/'
        );
        Object.keys(queryData || {}).forEach(function (key) {
            var value = queryData[key];
            if (value === undefined || value === null || value === '') return;
            url.searchParams.set(key, value);
        });
        return url.toString();
    }

    function normalizeAuthorization(value) {
        var text = String(value || '').trim();
        if (!text) return '';
        return /^Bearer\s+/i.test(text) ? text : 'Bearer ' + text;
    }

    function tokenForHyAppAPI(value) {
        return String(value || '').replace(/^Bearer\s+/i, '');
    }

    function splitHeaderPairs(value) {
        var result = {};
        String(value || '')
            .split(';')
            .forEach(function (item) {
                var index = item.indexOf('=');
                if (index > -1)
                    result[item.slice(0, index)] = item.slice(index + 1);
            });
        return result;
    }

    function putHeader(target, key, value) {
        if (
            value === undefined ||
            value === null ||
            value === '' ||
            target[key]
        )
            return;
        target[key] = String(value);
    }

    function normalizeHeaderCandidate(value, depth) {
        depth = depth || 0;
        if (depth > 4 || value === null || value === undefined) return {};
        if (typeof value === 'string') {
            var trimmed = value.trim();
            if (!trimmed) return {};
            if (trimmed.charAt(0) === '{' || trimmed.charAt(0) === '[') {
                try {
                    return normalizeHeaderCandidate(
                        JSON.parse(trimmed),
                        depth + 1
                    );
                } catch (_) {
                    return {};
                }
            }
            return trimmed ? { authorization: trimmed } : {};
        }
        if (Array.isArray(value)) {
            return value.reduce(function (result, item) {
                return Object.assign(
                    result,
                    normalizeHeaderCandidate(item, depth + 1)
                );
            }, {});
        }
        if (typeof value !== 'object') return {};

        var appIntel = splitHeaderPairs(
            value['Req-App-Intel'] || value['req-app-intel']
        );
        var sysOrigin = splitHeaderPairs(
            value['Req-Sys-Origin'] || value['req-sys-origin']
        );
        var normalized = {};
        putHeader(
            normalized,
            'authorization',
            value.Authorization ||
                value.authorization ||
                value.token ||
                value.accessToken
        );
        putHeader(
            normalized,
            'reqLang',
            value['Req-Lang'] ||
                value['req-lang'] ||
                value.reqLang ||
                value.lang
        );
        putHeader(
            normalized,
            'appVersion',
            appIntel.version || value.appVersion || value['App-Version']
        );
        putHeader(
            normalized,
            'buildVersion',
            appIntel.build || value.buildVersion
        );
        putHeader(normalized, 'model', appIntel.model || value.model);
        putHeader(normalized, 'channel', appIntel.channel || value.channel);
        putHeader(
            normalized,
            'reqImei',
            value['Req-Imei'] || value['req-imei'] || value.reqImei
        );
        putHeader(
            normalized,
            'origin',
            sysOrigin.origin || value.sysOrigin || value.origin
        );
        putHeader(
            normalized,
            'child',
            sysOrigin.originChild ||
                sysOrigin.child ||
                value.sysOriginChild ||
                value.child
        );

        ['headerInfo', 'headers', 'auth', 'data', 'state'].forEach(
            function (key) {
                Object.assign(
                    normalized,
                    normalizeHeaderCandidate(value[key], depth + 1)
                );
            }
        );
        return normalized;
    }

    function setHeadersFromApp(rawOrObject) {
        var data = normalizeHeaderCandidate(rawOrObject || {});
        var next = {};
        if (data.authorization)
            next.authorization = normalizeAuthorization(data.authorization);
        if (data.reqLang) next['req-lang'] = data.reqLang;
        if (
            data.appVersion ||
            data.buildVersion ||
            data.model ||
            data.channel
        ) {
            next['req-app-intel'] = [
                data.appVersion ? 'version=' + data.appVersion : '',
                data.buildVersion ? 'build=' + data.buildVersion : '',
                data.model ? 'model=' + data.model : '',
                data.channel ? 'channel=' + data.channel : '',
            ]
                .filter(Boolean)
                .join(';');
        }
        if (data.reqImei) next['req-imei'] = data.reqImei;
        if (data.origin) {
            next['req-sys-origin'] = [
                'origin=' + data.origin,
                'originChild=' + (data.child || data.origin),
            ].join(';');
        }
        headers = Object.assign(headers, next);

        if (window.HyAppAPI) {
            if (next.authorization)
                window.HyAppAPI.setAccessToken(
                    tokenForHyAppAPI(next.authorization)
                );
            window.HyAppAPI.setAppCode(APP_CODE);
        }
        return headers;
    }

    function discoverQueryHeaders() {
        return {
            authorization:
                query('authorization') ||
                query('Authorization') ||
                query('token') ||
                query('accessToken') ||
                query('access_token'),
            reqLang: query('lang') || query('language') || query('locale'),
            origin: query('sysOrigin') || query('origin') || 'YUMI',
            child: query('sysOriginChild') || query('originChild') || 'YUMI',
            channel: query('channel') || query('appChannel'),
        };
    }

    function readStorageHeaders(storage) {
        var collected = {};
        if (!storage) return collected;
        [
            'authorization',
            'Authorization',
            'token',
            'accessToken',
            'headerInfo',
            'headersFromApp',
            'appHeaders',
            'user',
            'userInfo',
        ].forEach(function (key) {
            try {
                Object.assign(
                    collected,
                    normalizeHeaderCandidate(storage.getItem(key))
                );
            } catch (_) {}
        });
        return collected;
    }

    function applyDiscoveredHeaders() {
        setHeadersFromApp(discoverQueryHeaders());
        setHeadersFromApp(window.__APP_HEADERS__);
        setHeadersFromApp(window.__HEADER_INFO__);
        setHeadersFromApp(window.headerInfo);
        try {
            setHeadersFromApp(readStorageHeaders(window.localStorage));
            setHeadersFromApp(readStorageHeaders(window.sessionStorage));
        } catch (_) {}
    }

    function ensureYumiAppCode() {
        if (window.HyAppAPI) window.HyAppAPI.setAppCode(APP_CODE);
        var params = currentParams();
        if (
            params.get('app_code') ||
            params.get('app') ||
            params.get('appCode')
        )
            return;
        if (!window.history || !window.history.replaceState) return;
        var url = new URL(window.location.href);
        url.searchParams.set('app_code', APP_CODE);
        // 目标仓 common/api.js 没有 app_code 会默认走 lalu；Yumi 页入口必须显式落到 Yumi 租户。
        window.history.replaceState(null, '', url.toString());
    }

    function isAppEnvironment() {
        return Boolean(
            window.app ||
            window.FlutterApp ||
            window.FlutterPageControl ||
            window.webkit
        );
    }

    function requestAccessOrigin() {
        return new Promise(function (resolve) {
            var settled = false;
            var timeoutId = null;
            function finish(raw) {
                if (raw) setHeadersFromApp(raw);
                if (settled) return;
                settled = true;
                if (timeoutId) window.clearTimeout(timeoutId);
                resolve(raw || null);
            }

            window.renderData = finish;
            window.getIosAccessOriginParam = finish;

            if (!isAppEnvironment()) {
                finish(null);
                return;
            }

            // Android 普通 WebView 会注入 window.app.getAccessOrigin；iOS/旧页可能只通过回调异步回填。
            if (
                window.app &&
                typeof window.app.getAccessOrigin === 'function'
            ) {
                try {
                    finish(window.app.getAccessOrigin());
                    return;
                } catch (_) {}
            }
            if (
                window.FlutterApp &&
                typeof window.FlutterApp.postMessage === 'function'
            ) {
                try {
                    window.FlutterApp.postMessage('requestAccessOrigin');
                } catch (_) {}
            }

            var attempt = 0;
            var poll = function () {
                attempt += 1;
                if (
                    window.app &&
                    typeof window.app.getAccessOrigin === 'function'
                ) {
                    try {
                        finish(window.app.getAccessOrigin());
                        return;
                    } catch (_) {}
                }
                if (!settled && attempt < 30) window.setTimeout(poll, 60);
            };
            poll();
            timeoutId = window.setTimeout(function () {
                finish(null);
            }, 1800);
        });
    }

    function connectToApp() {
        if (readyPromise) return readyPromise;
        ensureYumiAppCode();
        applyDiscoveredHeaders();
        readyPromise = requestAccessOrigin().then(function () {
            return {
                baseURL: baseURL(),
                headers: Object.assign({}, headers),
                authenticated: Boolean(headers.authorization),
            };
        });
        return readyPromise;
    }

    function parseResponse(response) {
        return response.text().then(function (text) {
            var payload = text ? JSON.parse(text) : {};
            if (!response.ok) {
                var httpError = new Error(
                    payload.message || response.statusText || 'request_failed'
                );
                httpError.status = response.status;
                httpError.payload = payload;
                throw httpError;
            }
            if (payload && payload.status === false) {
                var apiError = new Error(
                    payload.message || payload.errorMsg || 'api_request_failed'
                );
                apiError.payload = payload;
                throw apiError;
            }
            if (
                payload &&
                Object.prototype.hasOwnProperty.call(payload, 'body')
            )
                return payload.body;
            if (
                payload &&
                Object.prototype.hasOwnProperty.call(payload, 'data')
            )
                return payload.data;
            return payload;
        });
    }

    function request(path, options) {
        var opts = options || {};
        var body = opts.body;
        if (body && typeof body === 'object' && !(body instanceof FormData)) {
            body = JSON.stringify(body);
        }
        return connectToApp().then(function () {
            var requestHeaders = Object.assign({}, headers, opts.headers || {});
            if (!requestHeaders.authorization)
                delete requestHeaders.authorization;
            if (body)
                requestHeaders['content-type'] =
                    requestHeaders['content-type'] || 'application/json';
            return window
                .fetch(buildURL(path, opts.query), {
                    method: opts.method || 'GET',
                    headers: requestHeaders,
                    body: body,
                    credentials: 'omit',
                    cache: 'no-store',
                })
                .then(parseResponse);
        });
    }

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

    function relationType(tabOrType) {
        var key = String(tabOrType || 'cp')
            .trim()
            .toLowerCase();
        return (
            RELATION_TYPE_BY_TAB[key] || String(tabOrType || 'CP').toUpperCase()
        );
    }

    function userAvatar(profile) {
        profile = profile || {};
        return (
            profile.userAvatar ||
            profile.avatar ||
            profile.headImg ||
            profile.headImage ||
            ''
        );
    }

    function userId(profile) {
        profile = profile || {};
        return profile.id || profile.userId || profile.uid || '';
    }

    function choosePair(list, type) {
        var rows = Array.isArray(list) ? list : list ? [list] : [];
        for (var i = 0; i < rows.length; i += 1) {
            if (relationType(rows[i].relationType) === type) return rows[i];
        }
        return rows[0] || null;
    }

    function sortedLevels(levels) {
        return (Array.isArray(levels) ? levels : [])
            .slice()
            .sort(function (a, b) {
                return readNumber(a.level, 0) - readNumber(b.level, 0);
            });
    }

    function levelProgress(rights) {
        var intimacy = readNumber(rights && rights.intimacyValue, 0);
        var levels = sortedLevels(rights && rights.levels);
        var current = levels[0] || { level: 0, requiredIntimacyValue: 0 };
        var next = levels[1] || current;
        levels.forEach(function (level, index) {
            if (readNumber(level.requiredIntimacyValue, 0) <= intimacy) {
                current = level;
                next = levels[index + 1] || level;
            }
        });
        var currentThreshold = readNumber(current.requiredIntimacyValue, 0);
        var nextThreshold = Math.max(
            readNumber(next.requiredIntimacyValue, currentThreshold),
            currentThreshold
        );
        var currentExp = Math.max(0, intimacy - currentThreshold);
        var nextExp = Math.max(0, nextThreshold - currentThreshold);
        var progressPercent = nextExp ? (currentExp / nextExp) * 100 : 100;
        return {
            currentLevel: readNumber(current.level, 0),
            nextLevel: readNumber(next.level, current.level),
            currentExp: currentExp,
            nextExp: nextExp || intimacy,
            neededExp: Math.max(0, nextThreshold - intimacy),
            nextExpLevel: readNumber(next.level, current.level),
            progressPercent: Math.max(0, Math.min(100, progressPercent)),
        };
    }

    function normalizeRelation(pair, rights) {
        pair = pair || {};
        rights = rights || {};
        var progress = levelProgress(rights);
        var me = pair.meUserProfile || pair.me || {};
        var partner = pair.cpUserProfile || pair.partner || {};
        return Object.assign(progress, {
            relationType: relationType(
                pair.relationType || rights.relationType
            ),
            status: rights.relationshipStatus || pair.status || 'NONE',
            cpUserId: rights.cpUserId || userId(partner),
            days: readNumber(pair.days, 0),
            togetherDays: readNumber(pair.days, 0),
            me: { avatar: userAvatar(me), id: userId(me) },
            partner: { avatar: userAvatar(partner), id: userId(partner) },
            raw: { pair: pair, rights: rights },
        });
    }

    function pair(options) {
        var opts = options || {};
        return request('/user/cp-relationship/pair', {
            query: {
                relationType: relationType(opts.relationType || opts.tab),
                userId: opts.userId,
            },
        });
    }

    function rights(options) {
        var opts = options || {};
        return request('/user/cp/rights/config', {
            query: {
                relationType: relationType(opts.relationType || opts.tab),
                cpUserId: opts.cpUserId,
            },
        });
    }

    function loadRelation(options) {
        var opts = options || {};
        var type = relationType(opts.relationType || opts.tab);
        var selectedPair = null;
        var firstError = null;
        return pair({ relationType: type, userId: opts.userId })
            .then(function (pairList) {
                selectedPair = choosePair(pairList, type);
                var cpUserId =
                    opts.cpUserId ||
                    (selectedPair && userId(selectedPair.cpUserProfile)) ||
                    '';
                return rights({ relationType: type, cpUserId: cpUserId });
            })
            .catch(function (error) {
                firstError = error;
                return rights({ relationType: type, cpUserId: opts.cpUserId });
            })
            .then(function (rightsData) {
                return normalizeRelation(selectedPair, rightsData);
            })
            .catch(function (error) {
                throw firstError || error;
            });
    }

    function back() {
        if (
            window.FlutterPageControl &&
            window.FlutterPageControl.postMessage
        ) {
            window.FlutterPageControl.postMessage('close_page');
            return;
        }
        if (window.HyAppBridge && window.HyAppBridge.back) {
            window.HyAppBridge.back();
            return;
        }
        window.history.back();
    }

    window.YumiCommon = {
        baseURL: baseURL,
        buildURL: buildURL,
        headers: function () {
            return Object.assign({}, headers);
        },
        connectToApp: connectToApp,
        setHeadersFromApp: setHeadersFromApp,
        request: request,
        get: function (path, queryData) {
            return request(path, { method: 'GET', query: queryData });
        },
        post: function (path, body, queryData) {
            return request(path, {
                method: 'POST',
                body: body,
                query: queryData,
            });
        },
        back: back,
        cpSpace: {
            relationType: relationType,
            pair: pair,
            rights: rights,
            loadRelation: loadRelation,
            normalizeRelation: normalizeRelation,
        },
    };
})();
