import { useState, useEffect, useMemo } from 'react';
import { API_BASE_URL, IMAGE_BASE_URL } from '~/lib/api';

export interface APILocation {
  id: number;
  location: string;
  type?: string;
  coming_soon?: number;
  banner_picture?: string;
  description?: string;
}

export interface LocationItem {
  id: string;
  name: string;
  slug: string;
  meta: string;
  content: string;
  href: string;
  image: string;
}

const CACHE_KEY = 'nomadic-locations';
const CACHE_TTL_MS = 5 * 60 * 1000;

interface CachedLocations {
  data: APILocation[];
  timestamp: number;
}

// Module-level state shared across all hook instances
let resolvedData: APILocation[] | null = null;
let resolvedAt = 0;
let inflightRequest: Promise<APILocation[]> | null = null;
const subscribers = new Set<(data: APILocation[]) => void>();

const getCached = (): CachedLocations | null => {
  if (typeof window === 'undefined') return null;
  try {
    const raw = localStorage.getItem(CACHE_KEY);
    if (!raw) return null;
    return JSON.parse(raw) as CachedLocations;
  } catch {
    return null;
  }
};

const setCache = (data: APILocation[]): void => {
  if (typeof window === 'undefined') return;
  try {
    localStorage.setItem(CACHE_KEY, JSON.stringify({ data, timestamp: Date.now() }));
  } catch { /* ignore quota errors */ }
};

const notify = (data: APILocation[]) => {
  resolvedData = data;
  resolvedAt = Date.now();
  subscribers.forEach(fn => fn(data));
};

const loadLocations = async () => {
  // Already fetched this session and still fresh
  if (resolvedData && Date.now() - resolvedAt < CACHE_TTL_MS) return;

  // Check localStorage cache
  const cached = getCached();
  if (cached) {
    if (!resolvedData) notify(cached.data);
    if (Date.now() - cached.timestamp < CACHE_TTL_MS) return;
  }

  // Deduplicate in-flight requests
  if (inflightRequest) {
    await inflightRequest;
    return;
  }

  inflightRequest = (async () => {
    try {
      const res = await fetch(`${API_BASE_URL}/locations`, {
        headers: { Accept: 'application/json' },
      });
      if (!res.ok) return [];
      const json = await res.json();
      return (json?.data as APILocation[]) || [];
    } catch {
      return [];
    }
  })();

  try {
    const fresh = await inflightRequest;
    if (fresh.length > 0) {
      setCache(fresh);
      notify(fresh);
    }
  } finally {
    inflightRequest = null;
  }
};

const toSlug = (name: string): string =>
  name.toLowerCase().replace(/\s+/g, '-');

const normalizeBannerUrl = (url?: string): string => {
  if (!url) return '';
  if (url.startsWith('http')) return url;
  return `${IMAGE_BASE_URL}${url.startsWith('/') ? '' : '/'}${url}`;
};

export function apiLocationToItem(loc: APILocation): LocationItem {
  const slug = toSlug(loc.location);
  const name = loc.location.charAt(0).toUpperCase() + loc.location.slice(1);
  return {
    id: slug,
    name,
    slug,
    meta: loc.description || '',
    content: loc.description || '',
    href: `/locations/${slug}`,
    image: normalizeBannerUrl(loc.banner_picture),
  };
}

export function useLocations() {
  const [locations, setLocations] = useState<APILocation[]>(resolvedData || []);
  const [loading, setLoading] = useState(!resolvedData);

  useEffect(() => {
    const onUpdate = (data: APILocation[]) => {
      setLocations(data);
      setLoading(false);
    };

    subscribers.add(onUpdate);

    // If data already resolved, apply it immediately
    if (resolvedData) {
      setLocations(resolvedData);
      setLoading(false);
    }

    loadLocations();

    return () => { subscribers.delete(onUpdate); };
  }, []);

  const locationItems = useMemo(() => {
    const items: LocationItem[] = [];
    const seen = new Set<string>();
    for (const loc of locations) {
      if (loc.coming_soon) continue;
      const slug = toSlug(loc.location);
      if (seen.has(slug)) continue;
      seen.add(slug);
      items.push(apiLocationToItem(loc));
    }
    return items;
  }, [locations]);

  return { locations, locationItems, loading };
}
