import { ENV, STORAGE_KEYS } from './env';
import { version as packageVersion } from '@/package.json';

const CACHE_KEY = STORAGE_KEYS.APP_CONFIG || 'app_config_cache';
const DEFAULT_TTL_SECONDS = 3600;
let inFlight = null;
let lastConfig = null;

function buildUrl(base, path) {
  if (!base) return path;
  const normalizedBase = String(base).replace(/\/$/, '');
  const normalizedPath = String(path || '').replace(/^\//, '');
  return `${normalizedBase}/${normalizedPath}`;
}

function parseVersion(value) {
  if (!value) return [0];
  return String(value)
    .replace(/^v/i, '')
    .split('.')
    .map((item) => {
      const num = Number.parseInt(item, 10);
      return Number.isNaN(num) ? 0 : num;
    });
}

function compareVersion(a, b) {
  const left = parseVersion(a);
  const right = parseVersion(b);
  const maxLen = Math.max(left.length, right.length);
  for (let i = 0; i < maxLen; i += 1) {
    const l = left[i] || 0;
    const r = right[i] || 0;
    if (l > r) return 1;
    if (l < r) return -1;
  }
  return 0;
}

function getAppVersion() {
  let current = packageVersion || '0.0.0';
  // #ifdef MP-WEIXIN
  try {
    const account = uni.getAccountInfoSync && uni.getAccountInfoSync();
    const mpVersion = account && account.miniProgram && account.miniProgram.version;
    if (mpVersion) current = mpVersion;
  } catch (e) {
    // ignore
  }
  // #endif
  return current || '0.0.0';
}

function getCache() {
  try {
    return uni.getStorageSync(CACHE_KEY);
  } catch (e) {
    return null;
  }
}

function setCache(config) {
  const ttlSeconds = Number(config && config.ttlSeconds) || DEFAULT_TTL_SECONDS;
  const now = Date.now();
  const cache = {
    data: config.data,
    cachedAt: now,
    expireAt: now + ttlSeconds * 1000
  };
  uni.setStorageSync(CACHE_KEY, cache);
  return cache;
}

function isCacheValid(cache) {
  if (!cache || !cache.expireAt) return false;
  return Date.now() < cache.expireAt;
}

function applyConfig(config) {
  if (!config) return;
  if (config.api && config.api.baseUrl) {
    ENV.API_BASE_URL = config.api.baseUrl;
  }
  if (config.webview && config.webview.baseUrl) {
    ENV.WEBVIEW_BASE_URL = config.webview.baseUrl;
  }
  lastConfig = config;
}

function buildFailMessage(message) {
  return message || '配置获取失败，请退出小程序重新打开。';
}

function showExitModal(message) {
  uni.showModal({
    title: '提示',
    content: message,
    showCancel: false,
    confirmText: '退出',
    success: () => {
      // #ifdef MP-WEIXIN
      if (uni.exitMiniProgram) {
        uni.exitMiniProgram();
      }
      // #endif
      // #ifdef APP-PLUS
      if (typeof plus !== 'undefined' && plus.runtime && plus.runtime.quit) {
        plus.runtime.quit();
      }
      // #endif
    }
  });
}

function validateConfig(config) {
  if (!config) {
    return { ok: false, message: buildFailMessage('配置无效，请退出小程序重新打开。') };
  }
  if (config.disabled) {
    return {
      ok: false,
      message: config.disableReason || '服务暂不可用，请退出小程序重新打开。'
    };
  }

  const currentVersion = getAppVersion();
  const app = config.app || {};
  const api = config.api || {};
  const webview = config.webview || {};

  if (app.minVersion && compareVersion(currentVersion, app.minVersion) < 0) {
    return {
      ok: false,
      message: '当前版本过低，请退出小程序重新打开。'
    };
  }
  if (api.version && webview.version && api.version !== webview.version) {
    return {
      ok: false,
      message: '当前版本不一致，请退出小程序并重新打开以获取最新配置。'
    };
  }
  if (api.minClientVersion && compareVersion(currentVersion, api.minClientVersion) < 0) {
    return {
      ok: false,
      message: '当前版本过低，请退出小程序重新打开。'
    };
  }
  if (webview.minClientVersion && compareVersion(currentVersion, webview.minClientVersion) < 0) {
    return {
      ok: false,
      message: '当前版本过低，请退出小程序重新打开。'
    };
  }

  return { ok: true, message: '' };
}

function requestConfig() {
  const url = buildUrl(ENV.API_BASE_URL, '/api/open/app/config');
  return new Promise((resolve, reject) => {
    uni.request({
      url,
      method: 'GET',
      timeout: 8000,
      success: (res) => {
        if (res.statusCode >= 200 && res.statusCode < 300 && res.data) {
          resolve(res.data);
          return;
        }
        reject({ message: '配置获取失败', response: res });
      },
      fail: (err) => reject(err)
    });
  });
}

export async function initAppConfig(options = {}) {
  if (inFlight) return inFlight;
  const { force = false } = options;
  inFlight = (async () => {
    const cache = getCache();
    if (!force && isCacheValid(cache)) {
      const validation = validateConfig(cache.data);
      if (!validation.ok) {
        showExitModal(validation.message);
        throw new Error(validation.message);
      }
      applyConfig(cache.data);
      return cache.data;
    }

    try {
      const config = await requestConfig();
      const validation = validateConfig(config);
      if (!validation.ok) {
        showExitModal(validation.message);
        throw new Error(validation.message);
      }
      setCache(config);
      applyConfig(config);
      return config;
    } catch (error) {
    if (cache && isCacheValid(cache)) {
      const validation = validateConfig(cache.data);
      if (!validation.ok) {
        showExitModal(validation.message);
        throw new Error(validation.message);
      }
      applyConfig(cache.data);
      return cache.data;
    }
      showExitModal(buildFailMessage());
      throw error;
    }
  })();

  try {
    return await inFlight;
  } finally {
    inFlight = null;
  }
}

export async function ensureAppConfig() {
  const cache = getCache();
  console.log('【业务代码定位】', cache, new Error().stack);
  if (cache && isCacheValid(cache)) {
    const validation = validateConfig(cache.data);
    if (!validation.ok) {
      showExitModal(validation.message);
      throw new Error(validation.message);
    }
    applyConfig(cache.data);
    return cache.data;
  }
  return initAppConfig({ force: true });
}

export function getAppConfig() {
  return lastConfig || (getCache() ? getCache().data : null);
}

export function getWebviewBaseUrl() {
  const config = getAppConfig();
  let webviewBaseUrl = (config && config.webview && config.webview.baseUrl) || ENV.WEBVIEW_BASE_URL || '';
  console.log(webviewBaseUrl);
  return webviewBaseUrl;
}
