import { useEffect, useState } from 'react';

import { supabase } from './supabase';

export interface LinkPreview {
  url: string;
  title: string | null;
  description: string | null;
  imageUrl: string | null;
  siteName: string | null;
  ok: boolean;
}

// In-memory cache keyed by URL — avoids re-invoking the edge function for
// the same URL within a session even if many bubbles reference it.
const cache = new Map<string, LinkPreview | null>();
const inflight = new Map<string, Promise<LinkPreview | null>>();

async function loadPreview(url: string): Promise<LinkPreview | null> {
  if (cache.has(url)) return cache.get(url)!;
  const existing = inflight.get(url);
  if (existing) return existing;

  const p = (async () => {
    // First try the cache table directly (RLS allows authenticated reads).
    // Works offline-first if the server has already fetched this URL.
    // `link_previews` is a later migration — cast around stale generated types.
    const { data: cached } = await (supabase as unknown as {
      from: (t: string) => {
        select: (cols: string) => {
          eq: (col: string, val: string) => {
            maybeSingle: () => Promise<{
              data: {
                url: string;
                title: string | null;
                description: string | null;
                image_url: string | null;
                site_name: string | null;
                ok: boolean;
                fetched_at: string;
              } | null;
              error: Error | null;
            }>;
          };
        };
      };
    })
      .from('link_previews')
      .select('url, title, description, image_url, site_name, ok, fetched_at')
      .eq('url', url)
      .maybeSingle();
    if (cached && cached.ok) {
      const preview: LinkPreview = {
        url: cached.url,
        title: cached.title,
        description: cached.description,
        imageUrl: cached.image_url,
        siteName: cached.site_name,
        ok: cached.ok,
      };
      cache.set(url, preview);
      return preview;
    }

    try {
      const { data, error } = await supabase.functions.invoke('og-preview', {
        body: { url },
      });
      if (error) throw error;
      const preview = data as LinkPreview | null;
      cache.set(url, preview && preview.ok ? preview : null);
      return cache.get(url) ?? null;
    } catch {
      cache.set(url, null);
      return null;
    }
  })();

  inflight.set(url, p);
  try {
    return await p;
  } finally {
    inflight.delete(url);
  }
}

export function useLinkPreview(url: string | null): LinkPreview | null {
  const [preview, setPreview] = useState<LinkPreview | null>(() =>
    url ? cache.get(url) ?? null : null,
  );
  useEffect(() => {
    if (!url) {
      setPreview(null);
      return;
    }
    let cancelled = false;
    void loadPreview(url).then((p) => {
      if (!cancelled) setPreview(p);
    });
    return () => {
      cancelled = true;
    };
  }, [url]);
  return preview;
}

// Regex tuned for plain URLs inside message text. No markdown link syntax yet.
const URL_RE = /https?:\/\/[^\s<>"']+/i;

export function extractFirstUrl(text: string): string | null {
  const m = URL_RE.exec(text);
  return m?.[0] ?? null;
}
