// Main app — INLEARN Lead & Sales Flow (three-entity model: Contacts + Leads + Deals)

function App() {
  // ---------- Persisted state ----------
  const load = (key, fallback) => {
    try { const s = localStorage.getItem(key); if (s) return JSON.parse(s); } catch (e) {}
    return fallback;
  };
  const [contacts, setContacts]   = useState(() => load('INLEARN_CONTACTS_V1', CONTACTS));
  const [deals, setDeals]         = useState(() => load('INLEARN_DEALS_V1', DEALS));
  const [rawLeads, setRawLeads]   = useState(() => load('INLEARN_RAWLEADS_V1', RAW_LEADS));
  const [leadSources, setLeadSources] = useState(() => load('INLEARN_CRM_SOURCES_V2', DEFAULT_LEAD_SOURCES));
  const [stages, setStages]       = useState(() => load('INLEARN_CRM_STAGES_V2', DEFAULT_STAGES));
  const [playbooks, setPlaybooks] = useState(() => load('INLEARN_CRM_PLAYBOOKS_V2', DEFAULT_PLAYBOOKS));
  const [packages, setPackages] = useState(() => load('INLEARN_PACKAGES_V1', PRICING));
  const [subjects, setSubjects] = useState(() => load('INLEARN_SUBJECTS_V1', DEFAULT_SUBJECTS));
  const [team, setTeam] = useState(() => load('INLEARN_TEAM_V1', OWNERS));

  // Keep window.OWNERS in sync so every component reading the roster gets fresh members.
  window.OWNERS = team;

  // Keep the package catalog in sync with window.PRICING so the deal drawer's picker stays current.
  window.PRICING = packages;

  // Keep stage globals in sync for all components reading window.STAGES/STAGE_BY_ID/STAGE_INDEX
  window.STAGES = stages;
  window.STAGE_BY_ID = Object.fromEntries(stages.map(s => [s.id, s]));
  window.STAGE_INDEX = Object.fromEntries(stages.map((s, i) => [s.id, i]));
  // Expose contacts for the New Lead modal's phone auto-match
  window.__contactsForMatch = contacts;

  const [view, setView] = useState('dashboard');
  const [sidebarCollapsed, setSidebarCollapsed] = useState(() => load('INLEARN_CRM_SIDEBAR', false) === true || localStorage.getItem('INLEARN_CRM_SIDEBAR') === 'collapsed');
  const [selectedDeal, setSelectedDeal] = useState(null);
  const [selectedContact, setSelectedContact] = useState(null);
  const [selectedLeadRow, setSelectedLeadRow] = useState(null);
  const [qualifyingLead, setQualifyingLead] = useState(null);
  const [qualifyingRow, setQualifyingRow] = useState(null);
  const [selectedRawLead, setSelectedRawLead] = useState(null);
  const [search, setSearch] = useState('');
  const [newLeadOpen, setNewLeadOpen] = useState(false);

  // ---------- Persistence ----------
  useEffect(() => { localStorage.setItem('INLEARN_CONTACTS_V1', JSON.stringify(contacts)); }, [contacts]);
  useEffect(() => { localStorage.setItem('INLEARN_DEALS_V1', JSON.stringify(deals)); }, [deals]);
  useEffect(() => { localStorage.setItem('INLEARN_RAWLEADS_V1', JSON.stringify(rawLeads)); }, [rawLeads]);
  useEffect(() => { localStorage.setItem('INLEARN_CRM_SOURCES_V2', JSON.stringify(leadSources)); }, [leadSources]);
  useEffect(() => { localStorage.setItem('INLEARN_CRM_STAGES_V2', JSON.stringify(stages)); }, [stages]);
  useEffect(() => { localStorage.setItem('INLEARN_CRM_PLAYBOOKS_V2', JSON.stringify(playbooks)); }, [playbooks]);
  useEffect(() => { localStorage.setItem('INLEARN_PACKAGES_V1', JSON.stringify(packages)); }, [packages]);
  useEffect(() => { localStorage.setItem('INLEARN_SUBJECTS_V1', JSON.stringify(subjects)); }, [subjects]);
  useEffect(() => { localStorage.setItem('INLEARN_TEAM_V1', JSON.stringify(team)); }, [team]);
  useEffect(() => { localStorage.setItem('INLEARN_CRM_SIDEBAR', sidebarCollapsed ? 'collapsed' : 'expanded'); }, [sidebarCollapsed]);

  // Keep selected entities fresh
  useEffect(() => {
    if (selectedDeal) { const f = deals.find(d => d.id === selectedDeal.id); if (f && f !== selectedDeal) setSelectedDeal(f); }
  }, [deals]);
  useEffect(() => {
    if (selectedContact) { const f = contacts.find(c => c.id === selectedContact.id); if (f && f !== selectedContact) setSelectedContact(f); }
  }, [contacts]);

  // Keyboard shortcuts
  useEffect(() => {
    const onKey = (e) => {
      if ((e.metaKey || e.ctrlKey) && e.key === 'k') { e.preventDefault(); document.querySelector('input[type="text"]')?.focus(); }
      if (e.key === 'Escape') {
        if (qualifyingRow) setQualifyingRow(null);
        else if (qualifyingLead) setQualifyingLead(null);
        else if (selectedRawLead) setSelectedRawLead(null);
        else if (newLeadOpen) setNewLeadOpen(false);
        else if (selectedLeadRow) setSelectedLeadRow(null);
        else if (selectedDeal) setSelectedDeal(null);
        else if (selectedContact) setSelectedContact(null);
      }
    };
    window.addEventListener('keydown', onKey);
    return () => window.removeEventListener('keydown', onKey);
  }, [selectedDeal, selectedContact, qualifyingLead, qualifyingRow, newLeadOpen, selectedLeadRow, selectedRawLead]);

  // ---------- Deal actions ----------
  const updateDeal = (updated) => setDeals(prev => prev.map(d => d.id === updated.id ? updated : d));

  const moveDealStage = (dealId, targetStage) => {
    setDeals(prev => prev.map(d => {
      if (d.id !== dealId || d.stage === targetStage) return d;
      const fromLabel = STAGE_BY_ID[d.stage]?.label || d.stage;
      const toLabel = STAGE_BY_ID[targetStage]?.label || targetStage;
      return {
        ...d, stage: targetStage,
        registrationFormSubmitted: ['InvoiceSent','FulfillmentReady'].includes(targetStage) ? true : d.registrationFormSubmitted,
        invoicePaid: targetStage === 'FulfillmentReady' ? true : d.invoicePaid,
        wonAt: targetStage === 'FulfillmentReady' && !d.wonAt ? new Date().toISOString() : d.wonAt,
        invoiceNumber: targetStage === 'InvoiceSent' && !d.invoiceNumber ? `INV-2026-${String(Math.floor(Math.random()*900)+100)}` : d.invoiceNumber,
        invoiceAmount: targetStage === 'InvoiceSent' && !d.invoiceAmount ? d.customPackagePrice : d.invoiceAmount,
        notes: [{ id: 'n' + Date.now(), timestamp: new Date().toISOString(), text: `Moved from ${fromLabel} to ${toLabel}.`, author: 'You' }, ...d.notes],
      };
    }));
  };

  const deleteDeal = (id) => { setDeals(prev => prev.filter(d => d.id !== id)); setSelectedDeal(null); };

  // ---------- Contact actions ----------
  const updateContact = (updated) => setContacts(prev => prev.map(c => c.id === updated.id ? updated : c));
  const deleteContact = (id) => {
    setContacts(prev => prev.filter(c => c.id !== id)
      // also drop any relationship references pointing at the deleted contact
      .map(c => ({ ...c, relationships: (c.relationships || []).filter(r => r.contactId !== id) })));
    setSelectedContact(null);
  };

  // ---------- Lead actions ----------
  const createRawLead = (lead) => { setRawLeads(prev => [lead, ...prev]); setView('leads'); };

  const disqualifyLead = (lead) => {
    materializeLead({ leadId: lead.id, decision: lead.matchedContactId ? 'link' : 'create', matchedContactId: lead.matchedContactId, targetStage: 'LostDisqualified' });
  };

  const qualifyLead = ({ leadId, decision, matchedContactId, owner }) =>
    materializeLead({ leadId, decision, matchedContactId, targetStage: 'CallPending', owner });

  // Convert a raw lead into Contact(s) + a Deal at targetStage. Shared by qualify + disqualify.
  const materializeLead = ({ leadId, decision, matchedContactId, targetStage, owner }) => {
    const lead = rawLeads.find(l => l.id === leadId); if (!lead) return;
    const fa = lead.formAnswers;
    const isLost = targetStage === 'LostDisqualified';
    const tag = isLost ? 'Disqualified' : 'Newly qualified';
    const verb = isLost ? 'Disqualified' : 'Qualified';
    let payerId = matchedContactId, studentId = matchedContactId;
    let newContacts = [...contacts];

    if (decision === 'create' || !matchedContactId) {
      const selfStudent = fa.whoNeedsTutoring === 'Myself';
      const payer = {
        id: 'c-' + Date.now(),
        firstName: lead.name.split(' ')[0],
        lastName: lead.name.split(' ').slice(1).join(' ') || '',
        type: selfStudent ? 'Student' : 'Parent',
        email: lead.email, phone: lead.phone, addedAt: new Date().toISOString(),
        segment: selfStudent ? fa.segment : null,
        gradeOrYear: selfStudent ? fa.gradeOrYear : null,
        subjects: selfStudent ? fa.subjects : [],
        tags: [tag],
        notes: `${verb} from ${lead.source} lead on ${new Date().toLocaleDateString('en-ZA')}.`,
        relationships: [],
      };
      newContacts.push(payer);
      payerId = payer.id; studentId = payer.id;

      if (!selfStudent && fa.studentName) {
        const student = {
          id: 'c-' + (Date.now() + 1),
          firstName: fa.studentName.split(' ')[0],
          lastName: fa.studentName.split(' ').slice(1).join(' ') || payer.lastName,
          type: 'Student', email: '—', phone: '—', addedAt: new Date().toISOString(),
          segment: fa.segment, gradeOrYear: fa.gradeOrYear, subjects: fa.subjects,
          tags: [tag], notes: `Linked to ${payer.firstName} ${payer.lastName}.`,
          relationships: [{ kind: 'childOf', contactId: payer.id }],
        };
        newContacts.push(student);
        studentId = student.id;
        payer.relationships.push({ kind: 'parentOf', contactId: student.id });
      }
    } else {
      // Linking to existing contact: if the existing contact is a parent and a studentName is given,
      // create the student as their child; otherwise the matched contact is the student.
      const matched = contacts.find(c => c.id === matchedContactId);
      if (matched && matched.type === 'Parent' && fa.studentName) {
        const existingChild = newContacts.find(c =>
          c.relationships?.some(r => r.kind === 'childOf' && r.contactId === matched.id) &&
          contactFullName(c).toLowerCase() === fa.studentName.toLowerCase()
        );
        if (existingChild) {
          studentId = existingChild.id;
        } else {
          const student = {
            id: 'c-' + Date.now(),
            firstName: fa.studentName.split(' ')[0],
            lastName: fa.studentName.split(' ').slice(1).join(' ') || matched.lastName,
            type: 'Student', email: '—', phone: '—', addedAt: new Date().toISOString(),
            segment: fa.segment, gradeOrYear: fa.gradeOrYear, subjects: fa.subjects,
            tags: [tag], notes: `Linked to ${matched.firstName} ${matched.lastName}.`,
            relationships: [{ kind: 'childOf', contactId: matched.id }],
          };
          newContacts = newContacts.map(c => c.id === matched.id
            ? { ...c, relationships: [...(c.relationships||[]), { kind: 'parentOf', contactId: student.id }] } : c);
          newContacts.push(student);
          studentId = student.id;
        }
        payerId = matched.id;
      }
    }

    const newDeal = {
      id: 'd-' + Date.now(),
      title: `${fa.studentName || lead.name} — ${fa.subjects.join(' + ')}`,
      studentId, payerId,
      segment: fa.segment, gradeOrYear: fa.gradeOrYear, subjects: fa.subjects,
      struggleSubjectDetail: fa.struggle,
      stage: targetStage, owner: owner || 'gugu',
      disqualifiedReason: isLost ? 'Disqualified from inbox' : undefined,
      selectedPackage: null, customPackagePrice: null,
      registrationFormSubmitted: false, invoiceNumber: null, invoiceAmount: null, invoicePaid: false,
      followUpCount: 0, addedTime: new Date().toISOString(),
      utmSource: lead.source, utmCampaign: lead.campaign,
      notes: [{ id: 'n' + Date.now(), timestamp: new Date().toISOString(), text: `${verb} from lead. Enquiry: "${fa.struggle}"`, author: 'You' }],
    };

    setContacts(newContacts);
    setDeals(prev => [newDeal, ...prev]);
    setRawLeads(prev => prev.filter(l => l.id !== leadId));
    setQualifyingLead(null);
    setSelectedRawLead(null);
    if (!isLost) setSelectedDeal(newDeal);
  };

  // Navigation helpers (close one drawer when opening another)
  const openContact = (c) => { setSelectedDeal(null); setSelectedLeadRow(null); setSelectedContact(c); };
  const openDeal = (d) => { setSelectedContact(null); setSelectedLeadRow(null); setSelectedDeal(d); };

  // Synthesize lead rows from deals + contacts for the Leads table + detail drawer.
  const leadRows = useMemo(() => deals.map(d => {
    const student = getContact(contacts, d.studentId);
    const payer = getContact(contacts, d.payerId);
    const parentEnquiry = student && payer && student.id !== payer.id && payer.type === 'Parent';
    const contactInfo = (student && student.email !== '—') ? student : (payer || student);
    const whoNeeds = parentEnquiry ? `Parent (${payer.firstName})`
      : (student && payer && student.id !== payer.id) ? 'Someone else' : 'Themselves';
    return {
      id: d.id,
      // For a parent enquiry, the lead is the parent — the child shows beneath as "for …".
      name: parentEnquiry ? contactFullName(payer) : (student ? contactFullName(student) : d.title),
      studentName: student ? contactFullName(student) : null,
      studentId: d.studentId, payerId: d.payerId,
      contactInfoId: contactInfo ? contactInfo.id : null,
      email: contactInfo ? contactInfo.email : '—',
      phone: contactInfo ? contactInfo.phone : '—',
      segment: d.segment, gradeOrYear: d.gradeOrYear, subjects: d.subjects,
      stage: d.stage, addedTime: d.addedTime,
      source: d.utmSource, campaign: d.utmCampaign,
      struggle: d.struggleSubjectDetail, whoNeedsTutoring: whoNeeds, owner: d.owner,
    };
  }), [deals, contacts]);
  const openLeadRow = (row) => { setSelectedDeal(null); setSelectedContact(null); setSelectedLeadRow(row); };

  // Qualify from the lead drawer → open the two-step Qualify modal.
  const qualifyLeadRow = (row, match) => {
    const isParentEnquiry = row.studentName && row.studentName !== row.name;
    const fa = {
      whoNeedsTutoring: isParentEnquiry ? 'My Child' : 'Myself',
      studentName: isParentEnquiry ? row.studentName : null,
      segment: row.segment, gradeOrYear: row.gradeOrYear, subjects: row.subjects,
      struggle: row.struggle, budgetWilling: 'Yes', whenToStart: 'ASAP',
    };
    setQualifyingRow({
      id: row.id, name: row.name, email: row.email, phone: row.phone,
      source: row.source, campaign: row.campaign, submittedAt: row.addedTime,
      formAnswers: fa, matchedContactId: match ? match.id : null,
    });
  };
  const confirmQualifyRow = () => {
    if (qualifyingRow) moveDealStage(qualifyingRow.id, 'CallPending');
    setQualifyingRow(null);
    setSelectedLeadRow(null);
  };
  const disqualifyLeadRow = (row) => {
    moveDealStage(row.id, 'LostDisqualified');
    setSelectedLeadRow(null);
  };
  const assignLeadRow = (row, ownerId) => {
    setDeals(prev => prev.map(d => d.id === row.id ? { ...d, owner: ownerId } : d));
    setSelectedLeadRow({ ...row, owner: ownerId });
  };
  const deleteLeadRow = (row) => {
    setDeals(prev => prev.filter(d => d.id !== row.id));
    setSelectedLeadRow(null);
  };

  // Persist edits from the lead drawer back into the deal + linked contacts.
  const updateLeadRow = (edited) => {
    setDeals(prev => prev.map(d => d.id === edited.id ? {
      ...d,
      struggleSubjectDetail: edited.struggle,
      utmSource: edited.source,
      utmCampaign: edited.campaign,
      segment: edited.segment,
      gradeOrYear: edited.gradeOrYear,
      subjects: edited.subjects,
      owner: edited.owner,
    } : d));
    setContacts(prev => prev.map(c => {
      let next = c;
      // Student contact: keep name, level, subjects in sync
      if (c.id === edited.studentId) {
        const parts = (edited.name || '').trim().split(' ');
        next = { ...next, firstName: parts[0] || next.firstName, lastName: parts.slice(1).join(' '),
          segment: edited.segment, gradeOrYear: edited.gradeOrYear, subjects: edited.subjects };
      }
      // Whichever contact carries the contact details: update email/phone
      if (c.id === edited.contactInfoId) {
        next = { ...next, email: edited.email, phone: edited.phone };
      }
      return next;
    }));
    setSelectedLeadRow(edited);
  };

  return (
    <div className="min-h-screen bg-slate-50 text-slate-900 flex">
      <Sidebar view={view} setView={setView} contacts={contacts} deals={deals} rawLeads={rawLeads}
        collapsed={sidebarCollapsed} setCollapsed={setSidebarCollapsed}/>

      <div className="flex-1 min-w-0 flex flex-col">
        <Topbar view={view} onNewLead={() => setNewLeadOpen(true)} onSearch={setSearch} search={search}
          contacts={contacts} deals={deals}
          onJumpToContact={openContact} onJumpToDeal={openDeal}/>

        <main className="flex-1 overflow-y-auto">
          {view === 'dashboard' && <Dashboard deals={deals} contacts={contacts} rawLeads={rawLeads} onSelectDeal={openDeal} onSetView={setView}/>}
          {view === 'leads'     && <LeadsTable leads={leadRows} onSelectLead={openLeadRow} search={search}
            rawLeads={rawLeads} contacts={contacts} onQualifyRaw={setQualifyingLead} onDisqualifyRaw={disqualifyLead}
            onViewRaw={setSelectedRawLead}/>}
          {view === 'contacts'  && <ContactsView contacts={contacts} deals={deals} onSelectContact={openContact} search={search}/>}
          {view === 'deals'     && <DealsView deals={deals} contacts={contacts} onSelectDeal={openDeal} onSelectContact={openContact} onMoveDeal={moveDealStage} search={search}/>}
          {view === 'calls'     && <CallsView deals={deals} contacts={contacts} onSelectDeal={openDeal}/>}
          {view === 'reports'   && <ReportsView deals={deals} contacts={contacts}/>}
          {view === 'campaigns' && <CampaignsView deals={deals} rawLeads={rawLeads} leadSources={leadSources}/>}
          {view === 'services'  && <ServicesView packages={packages} setPackages={setPackages} subjects={subjects} setSubjects={setSubjects}/>}
          {view === 'playbook'  && <PlaybookView leads={deals} playbooks={playbooks} setPlaybooks={setPlaybooks} stages={stages}/>}
          {view === 'settings'  && <SettingsView leadSources={leadSources} setLeadSources={setLeadSources} stages={stages} setStages={setStages} leads={deals} setLeads={setDeals} team={team} setTeam={setTeam}/>}
        </main>
      </div>

      {selectedContact && (
        <ContactDrawer contact={selectedContact} contacts={contacts} deals={deals}
          onClose={() => setSelectedContact(null)}
          onSelectContact={openContact} onSelectDeal={openDeal} onUpdate={updateContact} onDelete={deleteContact}/>
      )}

      {selectedDeal && (
        <DealDrawer deal={selectedDeal} contacts={contacts} playbooks={playbooks}
          onClose={() => setSelectedDeal(null)}
          onUpdate={updateDeal} onMoveStage={moveDealStage} onDelete={deleteDeal}
          onSelectContact={openContact}/>
      )}

      {selectedLeadRow && (
        <LeadDetailDrawer lead={selectedLeadRow} contacts={contacts} leadSources={leadSources}
          onClose={() => setSelectedLeadRow(null)} onSelectContact={openContact} onSave={updateLeadRow}
          onQualify={qualifyLeadRow} onDisqualify={disqualifyLeadRow} onDelete={deleteLeadRow} onAssign={assignLeadRow}/>
      )}

      {qualifyingRow && (
        <QualifyModal lead={qualifyingRow} contacts={contacts}
          onClose={() => setQualifyingRow(null)} onConfirm={confirmQualifyRow}/>
      )}

      {qualifyingLead && (
        <QualifyModal lead={qualifyingLead} contacts={contacts}
          onClose={() => setQualifyingLead(null)} onConfirm={qualifyLead}/>
      )}

      {selectedRawLead && (
        <RawLeadDrawer lead={selectedRawLead} contacts={contacts}
          onClose={() => setSelectedRawLead(null)}
          onQualify={(l) => setQualifyingLead(l)}
          onDisqualify={disqualifyLead}
          onSelectContact={(c) => { setSelectedRawLead(null); openContact(c); }}/>
      )}

      <NewLeadModal open={newLeadOpen} onClose={() => setNewLeadOpen(false)} onCreate={createRawLead} leadSources={leadSources} subjects={subjects}/>
    </div>
  );
}

ReactDOM.createRoot(document.getElementById('root')).render(
  <AuthGate><App/></AuthGate>
);
