// services.jsx — client-side glue for the real backend.
//   • window.RR.generateResume(payload)  → POST /api/generate  (Gemini) → { resume, error }
//   • window.RR.rephraseBullet(opts)      → POST /api/rephrase  (Gemini)
//   • window.RR.helpPhrase(opts)          → POST /api/rephrase  (Gemini, "expand" mode)
//   • window.RR.auth.*                    → Supabase Auth (mock fallback when unconfigured)
//   • window.RR.db.*                      → resume persistence (Supabase, localStorage fallback)

(function () {
  const RR = (window.RR = window.RR || {});
  const CFG = window.RR_CONFIG || {};

  // ---- Gemini-backed endpoints (key lives server-side) --------------------
  async function postJSON(url, body) {
    const res = await fetch(url, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(body || {}),
    });
    let json = null;
    try { json = await res.json(); } catch (e) { /* non-JSON error body */ }
    if (!res.ok) {
      const msg = (json && (json.error || json.note)) || `HTTP ${res.status}`;
      const err = new Error(msg);
      err.status = res.status;
      throw err;
    }
    return json;
  }

  // Returns { resume, error }. error is null on success. Never silently returns a
  // sample — callers decide what to show when generation fails.
  RR.generateResume = async function (payload) {
    try {
      const out = await postJSON('/api/generate', payload);
      if (out && out.resume) return { resume: out.resume, error: null };
      return { resume: null, error: (out && out.note) || 'No resume returned.' };
    } catch (e) {
      console.warn('generateResume failed:', e.message);
      return { resume: null, error: e.message };
    }
  };

  RR.rephraseBullet = async function ({ text, role, tone, mode = 'rewrite' }) {
    try {
      const out = await postJSON('/api/rephrase', { text, role, tone, mode });
      return out && out.text ? out.text : null;
    } catch (e) {
      console.warn('rephrase failed:', e.message);
      return null;
    }
  };

  RR.helpPhrase = async function ({ text, question, role, tone }) {
    return RR.rephraseBullet({ text, role, tone, mode: 'expand' });
  };

  // ---- Supabase Auth ------------------------------------------------------
  let sb = null;
  const haveSupabase =
    CFG.SUPABASE_URL && CFG.SUPABASE_ANON_KEY &&
    window.supabase && typeof window.supabase.createClient === 'function';

  if (haveSupabase) {
    sb = window.supabase.createClient(CFG.SUPABASE_URL, CFG.SUPABASE_ANON_KEY);
  }
  RR.client = sb;
  RR.authEnabled = !!sb;

  // mock session store so the app still flows when Supabase isn't configured
  const mockUser = (email, name) => ({
    id: 'local',
    email: email || 'demo@resumerush.org',
    user_metadata: name ? { full_name: name } : {},
  });

  RR.auth = {
    enabled: !!sb,

    async signUp(email, password, fullName) {
      if (!sb) return { user: mockUser(email, fullName), error: null, mock: true };
      const { data, error } = await sb.auth.signUp({
        email, password,
        options: fullName ? { data: { full_name: fullName } } : undefined,
      });
      return { user: data?.user || null, session: data?.session || null, error };
    },

    async signIn(email, password) {
      if (!sb) return { user: mockUser(email), error: null, mock: true };
      const { data, error } = await sb.auth.signInWithPassword({ email, password });
      return { user: data?.user || null, session: data?.session || null, error };
    },

    async signInWithGoogle() {
      if (!sb) return { error: null, mock: true };
      const { data, error } = await sb.auth.signInWithOAuth({
        provider: 'google',
        options: { redirectTo: window.location.origin + window.location.pathname },
      });
      return { data, error };
    },

    async resetPassword(email) {
      if (!sb) return { error: null, mock: true };
      const { error } = await sb.auth.resetPasswordForEmail(email, {
        redirectTo: window.location.origin + window.location.pathname,
      });
      return { error };
    },

    async signOut() {
      if (!sb) return { error: null, mock: true };
      return sb.auth.signOut();
    },

    async getUser() {
      if (!sb) return null;
      const { data } = await sb.auth.getUser();
      return data?.user || null;
    },

    onChange(cb) {
      if (!sb) return () => {};
      const { data } = sb.auth.onAuthStateChange((_e, session) => cb(session?.user || null));
      return () => data?.subscription?.unsubscribe();
    },
  };

  // ---- Resume persistence -------------------------------------------------
  // Prefers Supabase (RLS-scoped to the signed-in user). Falls back to
  // localStorage transparently when Supabase is unconfigured OR a query fails
  // (e.g. the `resumes` table hasn't been created yet) — so saving always works.
  const LS_KEY = 'rr_resumes_v1';
  const nowISO = () => new Date().toISOString();
  const uuid = () =>
    (window.crypto && window.crypto.randomUUID)
      ? window.crypto.randomUUID()
      : 'id-' + Math.random().toString(36).slice(2) + Date.now().toString(36);

  function lsAll() {
    try { return JSON.parse(localStorage.getItem(LS_KEY) || '[]'); } catch (e) { return []; }
  }
  function lsWrite(arr) {
    try { localStorage.setItem(LS_KEY, JSON.stringify(arr)); } catch (e) { /* quota */ }
  }
  async function ownerId() {
    if (!sb) return 'local';
    const u = await RR.auth.getUser();
    return u?.id || 'local';
  }
  const useRemote = (owner) => sb && owner && owner !== 'local';

  RR.db = {
    async list() {
      const owner = await ownerId();
      if (useRemote(owner)) {
        try {
          const { data, error } = await sb.from('resumes').select('*').order('updated_at', { ascending: false });
          if (error) throw error;
          return data || [];
        } catch (e) { console.warn('db.list → localStorage:', e.message); }
      }
      return lsAll()
        .filter((r) => r.user_id === owner)
        .sort((a, b) => String(b.updated_at || '').localeCompare(String(a.updated_at || '')));
    },

    async get(id) {
      if (!id) return null;
      const owner = await ownerId();
      if (useRemote(owner)) {
        try {
          const { data, error } = await sb.from('resumes').select('*').eq('id', id).single();
          if (error) throw error;
          return data;
        } catch (e) { console.warn('db.get → localStorage:', e.message); }
      }
      return lsAll().find((r) => r.id === id) || null;
    },

    // save({ id?, title, target_role, data }) → row (with id). Insert when no id.
    async save({ id, title, target_role, data }) {
      const owner = await ownerId();
      if (useRemote(owner)) {
        try {
          if (id) {
            const { data: row, error } = await sb.from('resumes')
              .update({ title, target_role, data }).eq('id', id).select().single();
            if (error) throw error;
            return row;
          }
          const { data: row, error } = await sb.from('resumes')
            .insert({ user_id: owner, title, target_role, data }).select().single();
          if (error) throw error;
          return row;
        } catch (e) { console.warn('db.save → localStorage:', e.message); }
      }
      const all = lsAll();
      if (id) {
        const i = all.findIndex((r) => r.id === id);
        if (i >= 0) {
          all[i] = { ...all[i], title, target_role, data, updated_at: nowISO() };
          lsWrite(all);
          return all[i];
        }
      }
      const row = { id: uuid(), user_id: owner, title, target_role, data, created_at: nowISO(), updated_at: nowISO() };
      all.push(row);
      lsWrite(all);
      return row;
    },

    async rename(id, title) {
      const owner = await ownerId();
      if (useRemote(owner)) {
        try {
          const { data: row, error } = await sb.from('resumes').update({ title }).eq('id', id).select().single();
          if (error) throw error;
          return row;
        } catch (e) { console.warn('db.rename → localStorage:', e.message); }
      }
      const all = lsAll(); const i = all.findIndex((r) => r.id === id);
      if (i >= 0) { all[i] = { ...all[i], title, updated_at: nowISO() }; lsWrite(all); return all[i]; }
      return null;
    },

    async duplicate(id) {
      const src = await RR.db.get(id);
      if (!src) return null;
      return RR.db.save({ title: (src.title || 'Resume') + ' (copy)', target_role: src.target_role, data: src.data });
    },

    async remove(id) {
      const owner = await ownerId();
      if (useRemote(owner)) {
        try {
          const { error } = await sb.from('resumes').delete().eq('id', id);
          if (error) throw error;
          return true;
        } catch (e) { console.warn('db.remove → localStorage:', e.message); }
      }
      lsWrite(lsAll().filter((r) => r.id !== id));
      return true;
    },
  };

  // ---- In-progress survey autosave (localStorage, per user) ---------------
  // Lets a user stop mid-survey and resume from the dashboard. Kept in
  // localStorage (per device) — no extra table needed.
  const SURVEY_KEY = 'rr_survey_v1';
  function svAll() {
    try { return JSON.parse(localStorage.getItem(SURVEY_KEY) || '{}'); } catch (e) { return {}; }
  }
  function svWrite(obj) {
    try { localStorage.setItem(SURVEY_KEY, JSON.stringify(obj)); } catch (e) { /* quota */ }
  }
  RR.survey = {
    async save(state) {
      const owner = await ownerId();
      const all = svAll();
      all[owner] = { ...state, updated_at: nowISO() };
      svWrite(all);
    },
    async get() {
      const owner = await ownerId();
      return svAll()[owner] || null;
    },
    async clear() {
      const owner = await ownerId();
      const all = svAll();
      delete all[owner];
      svWrite(all);
    },
  };
})();
