// Molara — auth, talking to the real server.
//
// On a static (file://) preview the API isn't reachable, so we fall back to
// localStorage so the prototype still demos. On any http(s) host we use real
// sessions.
//
// Sessions: server returns a `sid` token in the JSON body of every successful
// /api/auth/*/{verify,signin}. We mirror it into localStorage and send it as
// `Authorization: Bearer <sid>` on every request. This works even when the
// browser refuses to set the cookie (Safari third-party blocking, embedded
// previews, http with Secure cookie, etc).

const AUTH_KEY = 'molara.auth.v1';
const SID_KEY = 'molara.sid.v1';
const AUTH_EVENT = 'molara:auth-change';
const API_ON = /^https?:$/.test(window.location.protocol);

const DEFAULT_USER = {
  name: 'Patient',
  initials: 'PT',
  email: '',
  phone: '',
  role: 'patient',
};

// ---------- localStorage fallback ----------
function loadAuth() {
  try { const raw = localStorage.getItem(AUTH_KEY); return raw ? JSON.parse(raw) : null; }
  catch (_) { return null; }
}
function saveAuth(u) {
  try { u ? localStorage.setItem(AUTH_KEY, JSON.stringify(u)) : localStorage.removeItem(AUTH_KEY); }
  catch (_) {}
}
function setAuth(u) {
  saveAuth(u);
  window.dispatchEvent(new CustomEvent(AUTH_EVENT, { detail: u }));
}

// ---------- Real API calls ----------
function getSid() { try { return localStorage.getItem(SID_KEY) || ''; } catch (_) { return ''; } }
function setSid(sid) {
  try { sid ? localStorage.setItem(SID_KEY, sid) : localStorage.removeItem(SID_KEY); } catch (_) {}
}
async function apiJson(path, opts = {}) {
  const sid = getSid();
  const res = await fetch(path, {
    credentials: 'include',
    headers: {
      'Content-Type': 'application/json',
      ...(sid ? { 'Authorization': `Bearer ${sid}` } : {}),
      ...(opts.headers || {}),
    },
    ...opts,
  });
  let data = null;
  try { data = await res.json(); } catch (_) {}
  if (!res.ok) {
    const err = new Error((data && data.error) || `HTTP ${res.status}`);
    err.status = res.status;
    throw err;
  }
  return data;
}

async function fetchMe() {
  if (!API_ON) return loadAuth();
  try {
    const data = await apiJson('/api/me');
    return data?.user || null;
  } catch (_) {
    return loadAuth();
  }
}

async function requestPatientOtp(email) {
  if (!API_ON) return { ok: true, sent: false, devCode: '000000' };
  return apiJson('/api/auth/patient/request', { method: 'POST', body: JSON.stringify({ email }) });
}

async function requestPatientPhoneOtp(phone) {
  if (!API_ON) return { ok: true, sent: false, devCode: '000000' };
  return apiJson('/api/auth/patient/request-phone', { method: 'POST', body: JSON.stringify({ phone }) });
}

async function verifyPatientOtp({ email, phone, code, name, method }) {
  if (!API_ON) {
    const fallbackId = email || phone || 'patient';
    const u = { ...DEFAULT_USER, email: email || '', phone: phone || '', name: name || fallbackId.split('@')[0], initials: initialsFor(name || fallbackId) };
    setAuth(u);
    return { ok: true, user: u };
  }
  const data = await apiJson('/api/auth/patient/verify', { method: 'POST', body: JSON.stringify({ email, phone, code, name, method }) });
  if (data?.sid) setSid(data.sid);
  if (data?.user) setAuth(data.user);
  return data;
}

async function doctorSignIn(name) {
  if (!API_ON) {
    const u = { role: 'doctor', name, initials: initialsFor(name), doctorId: 1 };
    setAuth(u);
    return { ok: true, user: u };
  }
  const data = await apiJson('/api/auth/doctor/signin', { method: 'POST', body: JSON.stringify({ name }) });
  if (data?.sid) setSid(data.sid);
  if (data?.user) setAuth(data.user);
  return data;
}

async function updatePatientProfile(profile) {
  if (!API_ON) {
    const current = loadAuth() || DEFAULT_USER;
    const name = String(profile?.name || current.name || 'Patient').trim();
    const u = { ...current, ...(profile || {}), name, initials: initialsFor(name) };
    setAuth(u);
    return { ok: true, user: u };
  }
  const data = await apiJson('/api/profile', { method: 'PUT', body: JSON.stringify(profile || {}) });
  if (data?.user) setAuth(data.user);
  return data;
}

async function signOutApi() {
  if (API_ON) {
    try { await apiJson('/api/auth/signout', { method: 'POST' }); } catch (_) {}
  }
  setSid('');
  setAuth(null);
}

function initialsFor(name) {
  const parts = String(name || '').trim().split(/\s+/).filter(Boolean);
  if (!parts.length) return 'PT';
  const skipDr = parts[0].replace(/\.$/, '').toLowerCase() === 'dr';
  const useParts = skipDr ? parts.slice(1) : parts;
  const src = useParts.length ? useParts : parts;
  return src.slice(0, 2).map((p) => p[0]).join('').toUpperCase();
}

// ---------- React hook ----------
function useAuth() {
  const [user, setUser] = React.useState(() => loadAuth());

  React.useEffect(() => {
    // Hydrate from server (real session) on mount — but only trust it if we
    // get a non-null user back. A null result during a sign-in race would
    // otherwise stomp the freshly-set state.
    fetchMe().then((u) => {
      if (u) {
        setUser(u);
        saveAuth(u);
      } else if (!getSid()) {
        // No sid means we're truly signed out; honor that.
        setUser(null);
        saveAuth(null);
      }
    });

    const handler = (e) => setUser(e.detail);
    window.addEventListener(AUTH_EVENT, handler);
    const storageHandler = (e) => { if (e.key === AUTH_KEY) setUser(loadAuth()); };
    window.addEventListener('storage', storageHandler);

    // Heartbeat so doctor presence stays accurate while page is open
    const beat = API_ON ? setInterval(() => {
      const sid = getSid();
      fetch('/api/presence/heartbeat', {
        method: 'POST', credentials: 'include',
        headers: sid ? { 'Authorization': `Bearer ${sid}` } : {},
      }).catch(() => {});
    }, 20000) : null;

    return () => {
      window.removeEventListener(AUTH_EVENT, handler);
      window.removeEventListener('storage', storageHandler);
      if (beat) clearInterval(beat);
    };
  }, []);

  const signIn = React.useCallback((overrides = {}) => {
    const u = { ...DEFAULT_USER, ...overrides };
    setAuth(u);
    return u;
  }, []);

  const signOut = React.useCallback(() => { signOutApi(); }, []);

  return { user, signedIn: !!user, signIn, signOut };
}

window.useAuth = useAuth;
window.signInUser = (overrides) => setAuth({ ...DEFAULT_USER, ...(overrides || {}) });
window.signOutUser = () => signOutApi();
window.molaraAuth = {
  requestPatientOtp,
  requestPatientPhoneOtp,
  verifyPatientOtp,
  doctorSignIn,
  updatePatientProfile,
  signOutApi,
  initialsFor,
  apiJson,
  getSid,
  setSid,
  API_ON,
};
