/**
 * Header-only JWT storage for web + Capacitor WebViews (#22).
 *
 * localStorage is the sync source of truth (axios interceptors).
 * When Capacitor Preferences is present, tokens are mirrored there so native
 * builds do not depend on third-party cookies (blocked in WKWebView).
 */

export const ACCESS_TOKEN_KEY = "access_token";
export const REFRESH_TOKEN_KEY = "refresh_token";

/**
 * Browsers can expose localStorage but throw on access (privacy mode / blocked storage).
 * @returns {Storage|null}
 */
function getLocalStorageSafe() {
  try {
    if (typeof window === "undefined" || !window.localStorage) {
      return null;
    }
    return window.localStorage;
  } catch {
    return null;
  }
}

/**
 * @returns {{ get?: Function, set?: Function, remove?: Function } | undefined}
 */
function getPreferencesPlugin() {
  if (typeof window === "undefined") {
    return undefined;
  }
  return window.Capacitor?.Plugins?.Preferences;
}

/**
 * @param {string} key
 * @returns {string|null}
 */
export function getToken(key) {
  const storage = getLocalStorageSafe();
  if (!storage) {
    return null;
  }
  try {
    return storage.getItem(key);
  } catch {
    return null;
  }
}

/**
 * @returns {string|null}
 */
export function getAccessToken() {
  return getToken(ACCESS_TOKEN_KEY);
}

/**
 * @returns {string|null}
 */
export function getRefreshToken() {
  return getToken(REFRESH_TOKEN_KEY);
}

/**
 * Persist tokens to localStorage and best-effort mirror to Capacitor Preferences.
 * @param {string} access
 * @param {string} [refresh]
 * @returns {Promise<void>}
 */
export async function setTokens(access, refresh) {
  const storage = getLocalStorageSafe();
  if (storage) {
    try {
      storage.setItem(ACCESS_TOKEN_KEY, access);
      if (refresh != null) {
        storage.setItem(REFRESH_TOKEN_KEY, refresh);
      }
    } catch {
      /* localStorage unavailable */
    }
  }

  const Preferences = getPreferencesPlugin();
  if (!Preferences?.set) {
    return;
  }

  const writes = [Preferences.set({ key: ACCESS_TOKEN_KEY, value: access })];
  if (refresh != null) {
    writes.push(Preferences.set({ key: REFRESH_TOKEN_KEY, value: refresh }));
  }
  await Promise.all(writes.map((p) => Promise.resolve(p).catch(() => undefined)));
}

/**
 * Clear tokens from localStorage and Preferences.
 * @returns {Promise<void>}
 */
export async function clearTokens() {
  const storage = getLocalStorageSafe();
  if (storage) {
    try {
      storage.removeItem(ACCESS_TOKEN_KEY);
      storage.removeItem(REFRESH_TOKEN_KEY);
    } catch {
      /* localStorage unavailable */
    }
  }

  const Preferences = getPreferencesPlugin();
  if (!Preferences?.remove) {
    return;
  }

  await Promise.all(
    [ACCESS_TOKEN_KEY, REFRESH_TOKEN_KEY].map((key) =>
      Promise.resolve(Preferences.remove({ key })).catch(() => undefined),
    ),
  );
}

/**
 * On native, hydrate localStorage from Preferences if local keys are empty.
 * Safe no-op on web / when Preferences missing.
 * @returns {Promise<{ access: string|null, refresh: string|null }>}
 */
export async function hydrateTokensFromNativeStorage() {
  const Preferences = getPreferencesPlugin();
  if (!Preferences?.get) {
    return { access: getAccessToken(), refresh: getRefreshToken() };
  }

  let access = getAccessToken();
  let refresh = getRefreshToken();

  if (!access) {
    try {
      const result = await Preferences.get({ key: ACCESS_TOKEN_KEY });
      if (result?.value) {
        const storage = getLocalStorageSafe();
        storage?.setItem(ACCESS_TOKEN_KEY, result.value);
        access = result.value;
      }
    } catch {
      /* ignore */
    }
  }

  if (!refresh) {
    try {
      const result = await Preferences.get({ key: REFRESH_TOKEN_KEY });
      if (result?.value) {
        const storage = getLocalStorageSafe();
        storage?.setItem(REFRESH_TOKEN_KEY, result.value);
        refresh = result.value;
      }
    } catch {
      /* ignore */
    }
  }

  return { access, refresh };
}

/**
 * Authorization header value for SimpleJWT (`AUTH_HEADER_TYPES`: JWT).
 * @param {string|null|undefined} access
 * @returns {string|null}
 */
export function authorizationHeader(access = getAccessToken()) {
  if (!access) {
    return null;
  }
  return `JWT ${access}`;
}
