const CANDIDATE_RELATIVE_PATHS = [
  './x_app_sdk_bundle.js',
  '../x_app_sdk_bundle.js',
  '../node_modules/x-app-sdk/dist/index.es.js',
];

const SDK_CANDIDATE_PATHS = CANDIDATE_RELATIVE_PATHS.map((relative) =>
  new URL(relative, import.meta.url).href,
);

const REQUIRED_METHODS = ['getToken', 'closeApp'];
const OPTIONAL_METHODS = [
  'configUIApp',
  'call',
  'sms',
  'vibrate',
  'currentLocation',
  'requestLocationPermission',
  'openPickerImage',
  'openPickerFile',
  'listenNotifiactionEvent',
  'paymentRequest',
  'listenPaymentEvent',
  'premissionsRequest',
  'saveStore',
  'getStore',
  'clearStore',
  'getInfo',
];
const KNOWN_METHODS = [...REQUIRED_METHODS, ...OPTIONAL_METHODS];

let cachedModulePromise = null;

function ensureSdkShape(module, source) {
  if (!module) {
    throw new Error(`Module from ${source} is undefined`);
  }
  for (const method of REQUIRED_METHODS) {
    if (typeof module[method] !== 'function') {
      throw new Error(`Module from ${source} is missing required export: ${method}`);
    }
  }
  const missingOptional = OPTIONAL_METHODS.filter(
    (method) => typeof module[method] !== 'function',
  );
  if (missingOptional.length) {
    console.warn(
      `⚠️ x-app-sdk module from ${source} missing optional exports: ${missingOptional.join(', ')}`,
    );
  }
}

async function importWithFallback() {
  let lastError;

  for (const path of SDK_CANDIDATE_PATHS) {
    try {
      const module = await import(path);
      ensureSdkShape(module, path);
      console.log(`✅ x-app-sdk loaded from ${path}`);
      console.log('🔧 SDK methods available:', Object.keys(module));
      try {
        Object.defineProperty(module, '__xAppSdkSource', {
          value: path,
          enumerable: false,
        });
      } catch (_) {}
      if (typeof document !== 'undefined' && document?.dispatchEvent) {
        document.dispatchEvent(
          new CustomEvent('xAppSdkReady', {
            detail: { source: path },
          }),
        );
      }
      return module;
    } catch (error) {
      lastError = error;
      console.warn(`ℹ️ Failed to load x-app-sdk from ${path}`, error);
    }
  }

  const message = 'Unable to locate x-app-sdk module';
  console.error(`❌ ${message}`);
  throw lastError ?? new Error(message);
}

export function resetCachedModule() {
  cachedModulePromise = null;
}

export async function loadXAppSdkModule() {
  if (!cachedModulePromise) {
    cachedModulePromise = importWithFallback();
  }
  return cachedModulePromise;
}

export async function bootstrapXAppSdk() {
  const module = await loadXAppSdkModule();
  return module;
}

function createMethodProxy(methodName) {
  return async (...args) => {
    const module = await loadXAppSdkModule();
    const target = module?.[methodName];
    if (typeof target !== 'function') {
      const available = Object.keys(module ?? {});
      throw new Error(
        `x-app-sdk method "${methodName}" is not available. Exported methods: ${available.join(', ')}`,
      );
    }
    return target(...args);
  };
}

const loaderApiMethods = KNOWN_METHODS.reduce((acc, methodName) => {
  acc[methodName] = createMethodProxy(methodName);
  return acc;
}, {});

const loaderApi = {
  loadXAppSdkModule,
  bootstrapXAppSdk,
  resetCachedModule,
  ...loaderApiMethods,
};

if (!globalThis.__xAppSdkLoader) {
  Object.defineProperty(globalThis, '__xAppSdkLoader', {
    value: loaderApi,
    writable: false,
    configurable: false,
  });
} else {
  Object.assign(globalThis.__xAppSdkLoader, loaderApi);
}
