// API client + React hooks for ClarionVote live API.
// Loaded AFTER data.jsx — window.CV_DATA must exist.
// Does NOT modify or replace any mock data.

const CV_API_BASE = 'https://api.clarionvote.com/api/v1';

// ─── Simple fetch-with-cache layer ─────────────────────────────────────
const _apiCache = {};
const _inflight = {};

function apiFetch(path, params = {}) {
  const qs = Object.entries(params)
    .filter(([, v]) => v != null && v !== '')
    .map(([k, v]) => `${k}=${encodeURIComponent(v)}`)
    .join('&');
  const url = `${CV_API_BASE}${path}${qs ? '?' + qs : ''}`;

  if (_apiCache[url] && Date.now() - _apiCache[url].ts < 5 * 60 * 1000) {
    return Promise.resolve(_apiCache[url].data);
  }
  if (_inflight[url]) return _inflight[url];

  _inflight[url] = fetch(url)
    .then(r => {
      if (!r.ok) throw new Error(`API ${r.status}`);
      return r.json();
    })
    .then(data => {
      _apiCache[url] = { data, ts: Date.now() };
      delete _inflight[url];
      return data;
    })
    .catch(err => {
      delete _inflight[url];
      throw err;
    });

  return _inflight[url];
}

// ─── Mock slug <-> API ID mapping ──────────────────────────────────────
// Only needed for politicians that exist in BOTH mock data and the API,
// so we can avoid duplicate search results.
const MOCK_TO_API_ID = {
  aoc: 290,
  cruz: 169,
  fetterman: 381,
  schumer: 108,
  gillibrand: 17,
  sanders: 3,
  warren: 157,
};

const API_ID_TO_MOCK = {};
for (const [mock, api] of Object.entries(MOCK_TO_API_ID)) {
  API_ID_TO_MOCK[api] = mock;
}

// ─── Convert API response to mock data shape ───────────────────────────
function apiToMockShape(api) {
  if (!api) return null;
  const firstTerm = (api.terms || []).reduce(
    (earliest, t) => (!earliest || t.start_date < earliest.start_date ? t : earliest),
    null
  );
  const since = firstTerm ? new Date(firstTerm.start_date).getFullYear() : null;
  const years = since ? new Date().getFullYear() - since : null;

  return {
    id: String(api.id),
    _apiId: api.id,
    _slug: api.slug,
    name: api.full_name,
    short: api.last_name,
    party: api.current_party,
    office: api.current_office,
    state: api.current_state,
    district: api.current_district,
    chamber: api.current_chamber
      ? api.current_chamber.charAt(0).toUpperCase() + api.current_chamber.slice(1)
      : null,
    level: api.level,
    photo: api.photo_url,
    twitter: api.twitter,
    facebook: api.facebook,
    instagram: api.instagram,
    youtube: api.youtube,
    website: api.official_url ? api.official_url.replace(/^https?:\/\//, '') : null,
    phone: api.office_phone,
    address: api.office_address,
    since,
    years,
    _fromApi: true,
  };
}

// ─── usePolitician(id) ────────────────────────────────────────────────
// Returns { data, loading, error }
// For mock politicians: returns mock data immediately (no API call).
// For non-mock: fetches from API, converts to mock shape.
function usePolitician(id) {
  const mockData = window.CV_DATA.POLITICIANS[id]
    || window.CV_DATA.STATE_REPS.find(x => x.id === id)
    || null;

  const [apiData, setApiData] = React.useState(null);
  const [loading, setLoading] = React.useState(false);
  const [error, setError] = React.useState(null);

  React.useEffect(() => {
    if (mockData) return; // mock is sufficient
    if (!id) return;

    setLoading(true);
    setError(null);
    setApiData(null);

    apiFetch(`/politicians/${id}`)
      .then(data => {
        setApiData(apiToMockShape(data));
        setLoading(false);
      })
      .catch(err => {
        setError(err.message);
        setLoading(false);
      });
  }, [id]);

  return {
    data: mockData || apiData,
    loading: !mockData && loading,
    error: !mockData ? error : null,
    isMock: !!mockData,
    apiId: mockData ? MOCK_TO_API_ID[id] || null : (apiData?._apiId || null),
  };
}

// ─── usePoliticianBills(apiId) ─────────────────────────────────────────
function usePoliticianBills(apiId) {
  const [bills, setBills] = React.useState(null);
  const [loading, setLoading] = React.useState(false);

  React.useEffect(() => {
    if (!apiId) return;
    setLoading(true);
    apiFetch(`/politicians/${apiId}/bills`)
      .then(res => { setBills(res.data || []); setLoading(false); })
      .catch(() => setLoading(false));
  }, [apiId]);

  return { bills, loading };
}

// ─── usePoliticianStats(apiId) ─────────────────────────────────────────
function usePoliticianStats(apiId) {
  const [stats, setStats] = React.useState(null);
  const [loading, setLoading] = React.useState(false);

  React.useEffect(() => {
    if (!apiId) return;
    setLoading(true);
    apiFetch(`/politicians/${apiId}/stats`)
      .then(res => { setStats(res); setLoading(false); })
      .catch(() => setLoading(false));
  }, [apiId]);

  return { stats, loading };
}

// ─── usePoliticianMisconduct(apiId) ────────────────────────────────────
function usePoliticianMisconduct(apiId) {
  const [misconduct, setMisconduct] = React.useState(null);
  const [loading, setLoading] = React.useState(false);

  React.useEffect(() => {
    if (!apiId) return;
    setLoading(true);
    apiFetch(`/politicians/${apiId}/misconduct`)
      .then(res => { setMisconduct(res.data || []); setLoading(false); })
      .catch(() => setLoading(false));
  }, [apiId]);

  return { misconduct, loading };
}

// ─── usePoliticianVotes(apiId, scope) ──────────────────────────────────
function usePoliticianVotes(apiId, scope) {
  const [votes, setVotes] = React.useState(null);
  const [loading, setLoading] = React.useState(false);

  React.useEffect(() => {
    if (!apiId) return;
    setLoading(true);
    apiFetch(`/politicians/${apiId}/votes`, { scope: scope || 'current', limit: 50 })
      .then(res => { setVotes(res.data || []); setLoading(false); })
      .catch(() => setLoading(false));
  }, [apiId, scope]);

  return { votes, loading };
}

// ─── useApiSearch(query) ───────────────────────────────────────────────
// Searches the API and returns results in a consistent shape.
// Excludes politicians that already exist in mock data (to avoid dupes).
function useApiSearch(query) {
  const [results, setResults] = React.useState([]);
  const [loading, setLoading] = React.useState(false);

  React.useEffect(() => {
    if (!query || query.length < 2) { setResults([]); return; }

    const timer = setTimeout(() => {
      setLoading(true);
      apiFetch('/politicians', { q: query, limit: 8 })
        .then(res => {
          const apiResults = (res.data || [])
            .filter(p => !API_ID_TO_MOCK[p.id]) // exclude mock dupes
            .map(p => ({
              id: String(p.id),
              name: p.full_name,
              party: p.current_party,
              office: p.current_office,
              state: p.current_state,
              district: p.current_district,
              photo: p.photo_url,
              _fromApi: true,
            }));
          setResults(apiResults);
          setLoading(false);
        })
        .catch(() => { setResults([]); setLoading(false); });
    }, 250); // debounce

    return () => clearTimeout(timer);
  }, [query]);

  return { results, loading };
}

// ─── useBills(params) ──────────────────────────────────────────────────
function useBills(params) {
  const [data, setData] = React.useState(null);
  const [loading, setLoading] = React.useState(false);
  const key = JSON.stringify(params || {});

  React.useEffect(() => {
    setLoading(true);
    apiFetch('/bills', params || {})
      .then(res => { setData(res); setLoading(false); })
      .catch(() => setLoading(false));
  }, [key]);

  return { data, loading };
}

// ─── Expose on window for other scripts ────────────────────────────────
window.CV_API = {
  BASE: CV_API_BASE,
  fetch: apiFetch,
  MOCK_TO_API_ID,
  API_ID_TO_MOCK,
  apiToMockShape,
};
