
import { getFacebookConfig } from './integrations';

declare global {
  interface Window {
    FB?: any;
    fbAsyncInit?: () => void;
  }
}

const SDK_URL = 'https://connect.facebook.net/en_US/sdk.js';
const TOKEN_KEY = 'asuka.facebook.access_token';

export type FacebookLoginState = {
  accessToken: string;
  userID?: string;
  expiresIn?: number;
};

export function getStoredFacebookToken(): string | null {
  try {
    const raw = localStorage.getItem(TOKEN_KEY);
    if (!raw) return null;
    const parsed = JSON.parse(raw) as { token: string; exp?: number };
    if (!parsed?.token) return null;
    if (parsed.exp && Date.now() > parsed.exp) return null;
    return parsed.token;
  } catch {
    return null;
  }
}

export function storeFacebookToken(token: string, expiresInSeconds?: number) {
  try {
    const exp = expiresInSeconds ? Date.now() + expiresInSeconds * 1000 : undefined;
    localStorage.setItem(TOKEN_KEY, JSON.stringify({ token, exp }));
  } catch {
    // ignore
  }
}

export function clearFacebookToken() {
  try {
    localStorage.removeItem(TOKEN_KEY);
  } catch {
    // ignore
  }
}

export async function loadFacebookSdk(): Promise<any> {
  const cfg = getFacebookConfig();
  if (!cfg) throw new Error('Facebook integration is not configured (missing appId).');

  if (window.FB) return window.FB;

  // If the script is already being loaded, wait for it.
  const existing = document.querySelector(`script[src="${SDK_URL}"]`) as HTMLScriptElement | null;
  if (existing) {
    await new Promise<void>((resolve, reject) => {
      const t = window.setTimeout(() => reject(new Error('Facebook SDK load timeout')), 15000);
      const check = () => {
        if (window.FB) {
          window.clearTimeout(t);
          resolve();
          return;
        }
        window.setTimeout(check, 50);
      };
      check();
    });
    return window.FB;
  }

  await new Promise<void>((resolve, reject) => {
    window.fbAsyncInit = () => {
      try {
        window.FB.init({
          appId: cfg.appId,
          cookie: true,
          xfbml: false,
          version: cfg.apiVersion,
        });
        resolve();
      } catch (e) {
        reject(e);
      }
    };

    const s = document.createElement('script');
    s.src = SDK_URL;
    s.async = true;
    s.defer = true;
    s.crossOrigin = 'anonymous';
    s.onerror = () => reject(new Error('Failed to load Facebook SDK'));
    document.head.appendChild(s);

    // safety timeout
    window.setTimeout(() => {
      if (!window.FB) reject(new Error('Facebook SDK load timeout'));
    }, 15000);
  });

  return window.FB;
}

export async function facebookLogin(): Promise<FacebookLoginState> {
  const cfg = getFacebookConfig();
  if (!cfg) throw new Error('Facebook integration is not configured (missing appId).');

  const FB = await loadFacebookSdk();

  const res = await new Promise<any>((resolve) => {
    FB.login((r: any) => resolve(r), { scope: cfg.scopes, return_scopes: true });
  });

  const auth = res?.authResponse;
  if (!auth?.accessToken) throw new Error('Facebook login was cancelled or did not return an access token.');

  storeFacebookToken(auth.accessToken, auth.expiresIn);
  return { accessToken: auth.accessToken, userID: auth.userID, expiresIn: auth.expiresIn };
}

export async function facebookLogout(): Promise<void> {
  const FB = await loadFacebookSdk();
  await new Promise<void>((resolve) => {
    try {
      FB.logout(() => resolve());
    } catch {
      resolve();
    }
  });
  clearFacebookToken();
}

export type GraphEdgeResponse<T> = {
  data: T[];
  paging?: { cursors?: { before?: string; after?: string }; next?: string };
};

export async function graphGet<T>(
  path: string,
  params: Record<string, string | number | boolean | undefined> = {},
  init?: { signal?: AbortSignal },
): Promise<T> {
  const cfg = getFacebookConfig();
  if (!cfg) throw new Error('Facebook integration is not configured (missing appId).');

  const token = getStoredFacebookToken();
  if (!token) throw new Error('Not authenticated with Facebook.');

  const url = new URL(`https://graph.facebook.com/${cfg.apiVersion}/${path.replace(/^\//, '')}`);
  url.searchParams.set('access_token', token);
  Object.entries(params).forEach(([k, v]) => {
    if (v === undefined) return;
    url.searchParams.set(k, String(v));
  });

  const r = await fetch(url.toString(), init?.signal ? { signal: init.signal } : undefined);
  const j = await r.json();
  if (!r.ok || j?.error) {
    const msg = j?.error?.message ? String(j.error.message) : `Graph API error (${r.status})`;
    throw new Error(msg);
  }
  return j as T;
}
