// Molara — shared data layer (talks to real API when available, localStorage otherwise)

const SPECIALTIES = [
  { k: 'emergency', n: 'Emergency dental consultation 24/7',      icon: 'shield',   count: 1 },
  { k: 'toothache', n: 'All types of tooth ache',                 icon: 'tooth',    count: 2 },
  { k: 'kids',      n: 'Kids tooth care',                         icon: 'baby',     count: 2 },
  { k: 'aligners',  n: 'Aligners and braces opinion',             icon: 'settings', count: 2 },
  { k: 'cosmetic',  n: 'Teeth whitening and cosmetic dental care', icon: 'sparkle',  count: 2 },
];

const DOCTORS = [
  { id: 1, n: 'Dr. Shivani Kumari',  creds: 'BDS', spec: 'Emergency Dentistry',                 k: 'emergency', covers: ['emergency','toothache','kids','aligners','cosmetic'], y: 5, loc: 'Hyderabad',          r: 4.9,  rv: 15, fee: 499, langs: ['Hindi', 'English', 'Bangla', 'Maithili'], online: false, bio: 'Dr. Shivani Kumari handles urgent dental triage across Molara, including pain, swelling, broken teeth, bleeding after dental work, and first-step guidance for every treatment category. She helps patients decide what can be managed online and when an in-clinic visit is needed.', avatar: 'SK', tone: 'rose',  wait: 'No waiting time' },
  { id: 2, n: 'Dr. Sakshi Sable',    creds: 'MDS', spec: 'Orthodontist',                         k: 'aligners',  covers: ['aligners'],                                  y: 5, loc: 'Pune',               r: 4.9,  rv: 12, fee: 699, langs: ['Hindi', 'English', 'Marathi'],          online: false, bio: 'Dr. Sakshi Sable focuses on braces, aligners, bite correction, retainer concerns, and second opinions for orthodontic treatment plans. She helps patients understand whether aligners or fixed braces may suit their dental condition.', avatar: 'SS', tone: 'amber', wait: '5 min' },
  { id: 3, n: 'Dr. Shirin Chavan',   creds: 'MDS', spec: 'Pediatric & Preventive Dentist',       k: 'kids',      covers: ['kids'],                                      y: 5, loc: 'Pune',               r: 4.8,  rv: 11, fee: 599, langs: ['English', 'Hindi', 'Marathi'],          online: false, bio: 'Dr. Shirin Chavan provides gentle online guidance for children\u2019s tooth pain, milk tooth concerns, early cavities, teething questions, brushing habits, and preventive care.', avatar: 'SC', tone: 'mint',  wait: '5 min' },
  { id: 4, n: 'Dr. Sanjana Murthy',  creds: 'BDS', spec: 'General Dentistry & Endodontics',      k: 'toothache', covers: ['toothache'],                                 y: 5, loc: 'Coimbatore, Tamil Nadu', r: 4.8, rv: 14, fee: 599, langs: ['Telugu', 'Tamil', 'Hindi', 'English'], online: false, bio: 'Dr. Sanjana Murthy supports patients with tooth ache, sensitivity, chewing pain, cavity concerns, and root canal second opinions.', avatar: 'SM', tone: 'blue',  wait: '5 min' },
  { id: 5, n: 'Dr. Neha Khandelwal', creds: 'BDS', spec: 'Cosmetic and Aesthetic Dentist',       k: 'cosmetic',  covers: ['cosmetic'],                                  y: 5, loc: 'Aligarh, UP',        r: 4.9,  rv: 10, fee: 699, langs: ['Hindi', 'English'],                    online: false, bio: 'Dr. Neha Khandelwal offers online opinions for teeth whitening, smile enhancement, stains, chipped tooth bonding, and cosmetic dentistry planning.', avatar: 'NK', tone: 'mint',  wait: '5 min' },
];

const DOC_BY_ID = (id) => DOCTORS.find(d => d.id === id) || DOCTORS[0];

const REVIEWS_KEY = 'molara.doctorReviews.v1';
const REVIEWS_EVENT = 'molara:doctor-reviews-change';
const MOLARA_API_ON = /^https?:$/.test(window.location.protocol);
const RECORDS_KEY = 'molara.records.v1';
const RECORDS_EVENT = 'molara:records-change';
const MESSAGES_KEY = 'molara.messages.v1';
const MESSAGES_EVENT = 'molara:messages-change';
const PRESENCE_EVENT = 'molara:presence-change';
const CONSULTS_KEY = 'molara.consults.v3';
const CONSULTS_EVENT = 'molara:consults-change';

window.__molaraConsultsCache = window.__molaraConsultsCache || null;
window.__molaraRecordsCache = window.__molaraRecordsCache || null;
window.__molaraMessagesCache = window.__molaraMessagesCache || {};
window.__molaraPresence = window.__molaraPresence || new Set();

async function molaraFetch(path, options = {}) {
  if (!MOLARA_API_ON) return null;
  let sid = '';
  try { sid = localStorage.getItem('molara.sid.v1') || ''; } catch (_) {}
  const res = await fetch(path, {
    credentials: 'include',
    ...options,
    headers: {
      'Content-Type': 'application/json',
      ...(sid ? { 'Authorization': `Bearer ${sid}` } : {}),
      ...(options.headers || {}),
    },
  });
  if (!res.ok) throw new Error(`Molara API ${res.status}`);
  return res.json();
}

function doctorMatchesSpec(doc, specK) {
  if (!specK || specK === 'all') return true;
  return doc.k === specK || (Array.isArray(doc.covers) && doc.covers.includes(specK));
}

// ----- Doctor reviews (still purely local, fine for testing) -----
function readDoctorReviews() {
  try { const raw = localStorage.getItem(REVIEWS_KEY); const d = raw ? JSON.parse(raw) : {}; return d && typeof d === 'object' ? d : {}; }
  catch (_) { return {}; }
}
function writeDoctorReviews(data) {
  try { localStorage.setItem(REVIEWS_KEY, JSON.stringify(data || {})); } catch (_) {}
  window.dispatchEvent(new CustomEvent(REVIEWS_EVENT, { detail: data || {} }));
}
function doctorStats(doc) {
  const d = typeof doc === 'number' ? DOC_BY_ID(doc) : doc;
  const live = readDoctorReviews()[d.id];
  return { rating: Number(live?.r ?? d.r).toFixed(1), reviews: Number(live?.rv ?? d.rv) };
}
function submitDoctorReview(docId, rating) {
  const doc = DOC_BY_ID(docId);
  const c = doctorStats(doc);
  const n = c.reviews + 1;
  const r = ((Number(c.rating) * c.reviews) + Number(rating || 5)) / n;
  const all = readDoctorReviews();
  all[doc.id] = { r: Math.round(r * 10) / 10, rv: n };
  writeDoctorReviews(all);
  return all[doc.id];
}
function useDoctorReviews() {
  const [reviews, setReviews] = React.useState(() => readDoctorReviews());
  React.useEffect(() => {
    const sync = () => setReviews(readDoctorReviews());
    const eventSync = (e) => setReviews(e.detail || readDoctorReviews());
    window.addEventListener(REVIEWS_EVENT, eventSync);
    window.addEventListener('storage', sync);
    return () => { window.removeEventListener(REVIEWS_EVENT, eventSync); window.removeEventListener('storage', sync); };
  }, []);
  return reviews;
}

// ----- Presence (which doctors are signed in right now) -----
async function syncPresence() {
  if (!MOLARA_API_ON) return;
  try {
    const data = await molaraFetch('/api/presence');
    const set = new Set(Array.isArray(data?.online) ? data.online : []);
    window.__molaraPresence = set;
    window.dispatchEvent(new CustomEvent(PRESENCE_EVENT, { detail: set }));
  } catch (_) {}
}
function usePresence() {
  const [online, setOnline] = React.useState(() => window.__molaraPresence || new Set());
  React.useEffect(() => {
    const handler = (e) => setOnline(new Set(e.detail));
    window.addEventListener(PRESENCE_EVENT, handler);
    syncPresence();
    const t = MOLARA_API_ON ? setInterval(syncPresence, 8000) : null;
    return () => { window.removeEventListener(PRESENCE_EVENT, handler); if (t) clearInterval(t); };
  }, []);
  return online;
}
function isDoctorOnline(docId) {
  return (window.__molaraPresence || new Set()).has(docId);
}

// ----- Consults -----
function formatSlot(slot) { return String(slot || '2:15p').replace('p', ' PM').replace('a', ' AM'); }
function todayBookingLabel() {
  const d = new Date();
  return `Today · ${d.toLocaleDateString('en-IN', { month: 'short' })} ${d.getDate()}`;
}
async function startEmergencyConsult(user) {
  if (!user || user.role === 'doctor') {
    window.requireAuth && window.requireAuth('/pay?emergency=1');
    return null;
  }
  const doc = DOC_BY_ID(1);
  const created = await createConsult({
    docId: doc.id,
    reason: 'Emergency dental consultation',
    severity: 10,
    mode: 'video',
    selectedDay: todayBookingLabel(),
    time: 'Immediate',
    fee: doc.fee,
    careType: 'Emergency 24/7',
    note: '24/7 emergency consult request',
    patientName: user?.name || 'New patient',
    patientInitials: user?.initials || 'PT',
  });
  if (created?.id) window.navigate && window.navigate('/pay?consult=' + encodeURIComponent(created.id));
  return created;
}
function readConsults() {
  if (Array.isArray(window.__molaraConsultsCache)) return window.__molaraConsultsCache;
  try { const raw = localStorage.getItem(CONSULTS_KEY); const list = raw ? JSON.parse(raw) : []; return Array.isArray(list) ? list : []; }
  catch (_) { return []; }
}
function writeConsults(list) {
  window.__molaraConsultsCache = Array.isArray(list) ? list : [];
  try { localStorage.setItem(CONSULTS_KEY, JSON.stringify(list)); } catch (_) {}
  window.dispatchEvent(new CustomEvent(CONSULTS_EVENT, { detail: list }));
}
async function syncConsultsFromServer() {
  if (!MOLARA_API_ON) return readConsults();
  try { const list = await molaraFetch('/api/consults'); writeConsults(Array.isArray(list) ? list : []); return readConsults(); }
  catch (_) { return readConsults(); }
}
async function updateConsult(id, patch) {
  const current = readConsults();
  const next = current.map((c) => c.id === id ? { ...c, ...patch, updatedAt: new Date().toISOString() } : c);
  writeConsults(next);
  if (MOLARA_API_ON) {
    try {
      const saved = await molaraFetch(`/api/consults/${encodeURIComponent(id)}`, { method: 'PATCH', body: JSON.stringify(patch) });
      if (saved) writeConsults(readConsults().map((c) => c.id === id ? saved : c));
    } catch (_) {}
  }
  return next.find((c) => c.id === id) || null;
}
async function createConsult(payload) {
  const doc = DOC_BY_ID(payload.docId);
  const fee = payload.fee ?? doc.fee;
  const consult = {
    id: 'MLR-' + new Date().getFullYear() + '-' + String(Date.now()).slice(-5),
    createdAt: new Date().toISOString(),
    status: 'confirmed',
    docId: doc.id,
    dentistName: doc.n,
    dentistInitials: doc.avatar,
    dentistSpec: doc.spec,
    dentistCreds: doc.creds,
    dentistTone: doc.tone,
    patientName: payload.patientName || 'New patient',
    patientInitials: payload.patientInitials || 'PT',
    reason: payload.reason,
    severity: payload.severity,
    careType: payload.careType,
    note: payload.note || '',
    followUp: !!payload.followUp,
    followUpFor: payload.followUpFor || null,
    followUpFreeUntil: payload.followUpFreeUntil || null,
    date: payload.selectedDay || todayBookingLabel(),
    time: payload.time || formatSlot(payload.slot),
    mode: payload.mode || 'video',
    fee,
  };
  if (MOLARA_API_ON) {
    try {
      const saved = await molaraFetch('/api/consults', { method: 'POST', body: JSON.stringify(consult) });
      if (saved) {
        const list = await syncConsultsFromServer();
        return saved;
      }
    } catch (_) {}
  }
  writeConsults([consult, ...readConsults().filter(c => c.id !== consult.id)]);
  return consult;
}

// ----- Payments / follow-up eligibility -----
// Returns { eligible, lastPaidConsultId, lastPaidAt, expiresAt } — used to decide
// whether the patient can skip the pay step (free follow-up within 7 days of paying
// the same dentist).
async function checkFollowupEligible(docId) {
  if (!MOLARA_API_ON) {
    // Local-only fallback
    const sevenDaysAgo = Date.now() - 7 * 24 * 60 * 60 * 1000;
    const last = readConsults()
      .filter((c) => Number(c.docId) === Number(docId) && c.paymentStatus === 'paid' && c.paidAt && new Date(c.paidAt).getTime() >= sevenDaysAgo)
      .sort((a, b) => new Date(b.paidAt) - new Date(a.paidAt))[0];
    return last
      ? { eligible: true, lastPaidConsultId: last.id, lastPaidAt: last.paidAt, expiresAt: new Date(new Date(last.paidAt).getTime() + 7*24*60*60*1000).toISOString() }
      : { eligible: false };
  }
  try { return await molaraFetch(`/api/payments/eligible?docId=${encodeURIComponent(docId)}`); }
  catch (_) { return { eligible: false }; }
}

async function chargeConsult({ consultId, amount, last4, method = 'card' }) {
  if (!MOLARA_API_ON) {
    // Local-only fallback
    const list = readConsults().map((c) => c.id === consultId
      ? { ...c, paymentStatus: 'paid', paidAt: new Date().toISOString(), paidAmount: amount, paidMethod: method, paidLast4: last4 }
      : c);
    writeConsults(list);
    return list.find((c) => c.id === consultId) || null;
  }
  try {
    const saved = await molaraFetch('/api/payments/charge', {
      method: 'POST',
      body: JSON.stringify({ consultId, amount, last4, method }),
    });
    if (saved) writeConsults(readConsults().map((c) => c.id === saved.id ? saved : c));
    return saved;
  } catch (_) { return null; }
}

// Is this consult joinable right now? — paid OR within 7-day follow-up window of a paid
// consult with the same dentist for this patient.
function consultIsJoinable(consult) {
  if (!consult) return { ok: false, reason: 'no-consult' };
  if (consult.paymentStatus === 'paid') return { ok: true };
  // Look for any prior paid consult with same dentist within 7 days
  const sevenDaysAgo = Date.now() - 7 * 24 * 60 * 60 * 1000;
  const all = readConsults();
  const last = all
    .filter((c) => c.id !== consult.id
      && Number(c.docId) === Number(consult.docId)
      && c.patientId === consult.patientId
      && c.paymentStatus === 'paid'
      && c.paidAt
      && new Date(c.paidAt).getTime() >= sevenDaysAgo)
    .sort((a, b) => new Date(b.paidAt) - new Date(a.paidAt))[0];
  return last
    ? { ok: true, viaFollowup: true, lastPaidAt: last.paidAt }
    : { ok: false, reason: 'unpaid' };
}
function latestConsult() { return readConsults()[0] || null; }
function useConsults() {
  const [consults, setConsults] = React.useState(() => readConsults());
  React.useEffect(() => {
    const sync = () => setConsults(readConsults());
    const eventSync = (e) => setConsults(Array.isArray(e.detail) ? e.detail : readConsults());
    window.addEventListener(CONSULTS_EVENT, eventSync);
    window.addEventListener('storage', sync);
    syncConsultsFromServer().then(sync);
    const poll = MOLARA_API_ON ? setInterval(() => syncConsultsFromServer().then(sync), 3000) : null;
    return () => { window.removeEventListener(CONSULTS_EVENT, eventSync); window.removeEventListener('storage', sync); if (poll) clearInterval(poll); };
  }, []);
  return consults;
}
function clearConsults() { writeConsults([]); }

// ----- Records -----
function readRecords() {
  if (Array.isArray(window.__molaraRecordsCache)) return window.__molaraRecordsCache;
  try { const raw = localStorage.getItem(RECORDS_KEY); const list = raw ? JSON.parse(raw) : []; return Array.isArray(list) ? list : []; }
  catch (_) { return []; }
}
function writeRecords(list) {
  window.__molaraRecordsCache = Array.isArray(list) ? list : [];
  try { localStorage.setItem(RECORDS_KEY, JSON.stringify(window.__molaraRecordsCache)); } catch (_) {}
  window.dispatchEvent(new CustomEvent(RECORDS_EVENT, { detail: window.__molaraRecordsCache }));
}
async function syncRecordsFromServer() {
  if (!MOLARA_API_ON) return readRecords();
  try { const list = await molaraFetch('/api/records'); writeRecords(Array.isArray(list) ? list : []); }
  catch (_) {}
  return readRecords();
}
async function createRecord(record) {
  if (MOLARA_API_ON) {
    try {
      const saved = await molaraFetch('/api/records', { method: 'POST', body: JSON.stringify(record) });
      if (saved) {
        await syncRecordsFromServer();
        return saved;
      }
    } catch (_) {}
  }
  const next = { id: record.id || String(Date.now()), createdAt: record.createdAt || new Date().toISOString(), ...record };
  writeRecords([next, ...readRecords()]);
  return next;
}
function useRecords() {
  const [records, setRecords] = React.useState(() => readRecords());
  React.useEffect(() => {
    const sync = () => setRecords(readRecords());
    const eventSync = (e) => setRecords(Array.isArray(e.detail) ? e.detail : readRecords());
    window.addEventListener(RECORDS_EVENT, eventSync);
    window.addEventListener('storage', sync);
    syncRecordsFromServer().then(sync);
    const poll = MOLARA_API_ON ? setInterval(() => syncRecordsFromServer().then(sync), 4000) : null;
    return () => { window.removeEventListener(RECORDS_EVENT, eventSync); window.removeEventListener('storage', sync); if (poll) clearInterval(poll); };
  }, []);
  return records;
}

// ----- Messages -----
function readMessages(consultId = 'default') {
  if (Array.isArray(window.__molaraMessagesCache[consultId])) return window.__molaraMessagesCache[consultId];
  try { const raw = localStorage.getItem(MESSAGES_KEY); const all = raw ? JSON.parse(raw) : {}; return Array.isArray(all[consultId]) ? all[consultId] : []; }
  catch (_) { return []; }
}
function writeMessages(consultId, list) {
  window.__molaraMessagesCache[consultId] = Array.isArray(list) ? list : [];
  try {
    const raw = localStorage.getItem(MESSAGES_KEY);
    const all = raw ? JSON.parse(raw) : {};
    all[consultId] = window.__molaraMessagesCache[consultId];
    localStorage.setItem(MESSAGES_KEY, JSON.stringify(all));
  } catch (_) {}
  window.dispatchEvent(new CustomEvent(MESSAGES_EVENT, { detail: { consultId, list: window.__molaraMessagesCache[consultId] } }));
}
async function syncMessagesFromServer(consultId = 'default') {
  if (!MOLARA_API_ON) return readMessages(consultId);
  try { const list = await molaraFetch(`/api/messages?consultId=${encodeURIComponent(consultId)}`); writeMessages(consultId, Array.isArray(list) ? list : []); }
  catch (_) {}
  return readMessages(consultId);
}
async function sendVisitMessage(consultId, from, text) {
  const trimmed = String(text || '').trim();
  if (!trimmed) return null;
  if (MOLARA_API_ON) {
    try {
      const saved = await molaraFetch('/api/messages', { method: 'POST', body: JSON.stringify({ consultId, from, text: trimmed }) });
      if (saved) {
        await syncMessagesFromServer(consultId);
        return saved;
      }
    } catch (_) {}
  }
  const next = { id: String(Date.now()), consultId, from, text: trimmed, createdAt: new Date().toISOString() };
  writeMessages(consultId, [...readMessages(consultId), next]);
  return next;
}
function useVisitMessages(consultId = 'default') {
  const [messages, setMessages] = React.useState(() => readMessages(consultId));
  React.useEffect(() => {
    const sync = () => setMessages(readMessages(consultId));
    const eventSync = (e) => { if (e.detail?.consultId === consultId) setMessages(e.detail.list || readMessages(consultId)); };
    window.addEventListener(MESSAGES_EVENT, eventSync);
    syncMessagesFromServer(consultId).then(sync);
    const poll = MOLARA_API_ON ? setInterval(() => syncMessagesFromServer(consultId).then(sync), 1500) : null;
    return () => { window.removeEventListener(MESSAGES_EVENT, eventSync); if (poll) clearInterval(poll); };
  }, [consultId]);
  return messages;
}

const TONE_BG = { rose: 'oklch(94% 0.04 25)', mint: 'oklch(94% 0.05 165)', blue: 'oklch(94% 0.04 240)', amber: 'oklch(94% 0.05 80)' };
const TONE_FG = { rose: 'oklch(45% 0.12 25)', mint: 'oklch(38% 0.10 165)', blue: 'oklch(38% 0.13 240)', amber: 'oklch(40% 0.10 80)' };

Object.assign(window, {
  DOCTORS, SPECIALTIES, DOC_BY_ID, TONE_BG, TONE_FG,
  CONSULTS_KEY, CONSULTS_EVENT, REVIEWS_KEY, REVIEWS_EVENT,
  RECORDS_KEY, RECORDS_EVENT, MESSAGES_KEY, MESSAGES_EVENT, PRESENCE_EVENT,
  MOLARA_API_ON,
  doctorMatchesSpec, readDoctorReviews, writeDoctorReviews,
  doctorStats, submitDoctorReview, useDoctorReviews,
  readConsults, writeConsults, syncConsultsFromServer,
  updateConsult, createConsult, startEmergencyConsult, latestConsult, useConsults, clearConsults,
  readRecords, writeRecords, createRecord, useRecords, syncRecordsFromServer,
  readMessages, writeMessages, syncMessagesFromServer, sendVisitMessage, useVisitMessages,
  formatSlot, syncPresence, usePresence, isDoctorOnline,
  checkFollowupEligible, chargeConsult, consultIsJoinable,
});
