// ══════════════════════════════════════════════════════════
// Main app — state, URL params, event reporting, Tweaks wiring
// ══════════════════════════════════════════════════════════

const EVENT_ENDPOINT = 'https://hooks.example.com/events';

function getParam(n){ return new URLSearchParams(window.location.search).get(n) || ''; }
function getSessionId(){
  let id = sessionStorage.getItem('content_session_id');
  if(!id){ id = crypto.randomUUID(); sessionStorage.setItem('content_session_id', id); }
  return id;
}
const pageLoadTime = Date.now();

function reportEvent(eventType, metadata = {}, tier = 'granular'){
  const payload = {
    event: eventType,
    event_tier: tier,
    timestamp: new Date().toISOString(),
    page: {
      type: document.body.dataset.pageType,
      slug: document.body.dataset.pageSlug,
      product: document.body.dataset.product,
      vertical: document.body.dataset.vertical,
      audience: document.body.dataset.audience,
      mode: null, complexity_tier: null,
      url: window.location.href
    },
    professional: {
      id: getParam('advisor_id') || null,
      name: getParam('name') || null,
      firm: getParam('firm') || null,
      email: getParam('email') || null
    },
    client: {
      id: sessionStorage.getItem('content_client_id') || null,
      email: null,
      name: getParam('client') || null
    },
    session: { id: getSessionId(), referrer: document.referrer || null },
    metadata
  };
  fetch(EVENT_ENDPOINT, {
    method:'POST', headers:{'Content-Type':'application/json'},
    body: JSON.stringify(payload), keepalive: true
  }).catch(()=>{});
}
function reportMilestone(m, metadata={}){ reportEvent(m, metadata, 'milestone'); }

function App(){
  // ── URL params → advisor + client
  const urlAdvisor = {
    name: getParam('name'),
    firm: getParam('firm'),
    email: getParam('email'),
    phone: getParam('phone'),
    booking: getParam('booking'),
    servicePage: getParam('service_page')
  };
  const hasAdvisor = !!(urlAdvisor.name && urlAdvisor.firm && urlAdvisor.email);
  const [advisor, setAdvisor] = useState(hasAdvisor ? urlAdvisor : {
    name: 'Jane Smith', firm: 'Smith Financial',
    email: 'jane@smithfinancial.ca', phone: '(416) 555-0142',
    booking: 'https://calendly.com/jane-smith', servicePage: ''
  });
  const [clientName, setClientName] = useState(getParam('client') || '');
  const [shareUrl, setShareUrl] = useState('');
  const [setupOpen, setSetupOpen] = useState(!hasAdvisor);

  // ── Tweaks
  const [tweaks, setTweaks] = useState(window.TWEAK_DEFAULTS);
  const [tweaksOpen, setTweaksOpen] = useState(false);
  const [resourceModal, setResourceModal] = useState(null);

  // ── Demo state
  const demoPreset = DEMO_STATES[tweaks.demoState] || DEMO_STATES.midyear;
  const [completed, setCompleted] = useState(new Set(demoPreset.completed));
  const [reminders, setReminders] = useState(new Set(demoPreset.reminders));
  const [committed, setCommitted] = useState(demoPreset.accountabilityCommitted);
  const forceOverdue = useMemo(() => new Set(demoPreset.forceOverdue || []), [tweaks.demoState]);
  const overdueDates = useMemo(() => demoPreset.overdueDates || {}, [tweaks.demoState]);
  const [viewedResources, setViewedResources] = useState(new Set());

  // ── Compliance state
  const [complianceItems, setComplianceItems] = useState(() =>
    COMPLIANCE.items.map(i => ({ ...i }))
  );
  function toggleCompliance(id, evt){
    const pt = getClickPoint(evt);
    setComplianceItems(items => items.map(item => {
      if(item.id !== id) return item;
      const nowDone = !item.completed;
      if(nowDone){
        const today = new Date().toLocaleDateString('en-CA', { month:'short', day:'numeric', year:'numeric' });
        showToast(`✓ ${item.title} recorded`);
        reportEvent('compliance_item_completed', { item_id: id, item_title: item.title });
        if(pt) fireConfetti(pt.x, pt.y, { count: 22, power: 9 });
        setTimeout(() => checkHealthMilestone(), 50);
        return { ...item, completed: true, completedDate: today, overdue: false };
      }
      return { ...item, completed: false };
    }));
  }

  // When demo state changes, reset progress
  useEffect(() => {
    const p = DEMO_STATES[tweaks.demoState] || DEMO_STATES.midyear;
    setCompleted(new Set(p.completed));
    setReminders(new Set(p.reminders));
    setCommitted(p.accountabilityCommitted);
  }, [tweaks.demoState]);

  // If no client name from URL, show demo name
  const effectiveClient = clientName || demoPreset.clientName;

  // ── Body accent attribute for CSS theming
  useEffect(() => {
    document.body.setAttribute('data-accent', tweaks.accent);
  }, [tweaks.accent]);

  // ── AUAA milestone tracking
  const pillarsFired = useRef({ awareness:false, understanding:false, action:false, accountability:false });

  // Awareness: 30 s on page + scrolled past hero
  useEffect(() => {
    function check(){
      if(pillarsFired.current.awareness) return;
      const hero = document.querySelector('.hero');
      if(!hero) return;
      const heroBottom = hero.getBoundingClientRect().bottom;
      const t = (Date.now() - pageLoadTime) / 1000;
      if(heroBottom < 0 && t > 30){
        pillarsFired.current.awareness = true;
        reportMilestone('awareness_reached', { trigger:'scrolled_past_hero_with_time', time_on_page_s: Math.round(t) });
      }
    }
    const i = setInterval(check, 2000);
    window.addEventListener('scroll', check, { passive:true });
    return () => { clearInterval(i); window.removeEventListener('scroll', check); };
  }, []);

  // Understanding: user has opened 2+ resources OR reached phases section + viewed 2+ activity details
  function maybeFireUnderstanding(){
    if(pillarsFired.current.understanding) return;
    if(viewedResources.size >= 2){
      pillarsFired.current.understanding = true;
      reportMilestone('understanding_confirmed', { trigger:'multiple_resources_opened', count: viewedResources.size });
    }
  }
  useEffect(maybeFireUnderstanding, [viewedResources]);

  // ── Event-reporting edit-mode bridge to parent
  useEffect(() => {
    function handle(e){
      const d = e.data || {};
      if(d.type === '__activate_edit_mode') setTweaksOpen(true);
      else if(d.type === '__deactivate_edit_mode') setTweaksOpen(false);
    }
    window.addEventListener('message', handle);
    try { window.parent.postMessage({type:'__edit_mode_available'}, '*'); } catch(_){}
    return () => window.removeEventListener('message', handle);
  }, []);

  function setTweak(key, value){
    const next = { ...tweaks, [key]: value };
    setTweaks(next);
    try {
      window.parent.postMessage({ type:'__edit_mode_set_keys', edits:{ [key]: value } }, '*');
    } catch(_){}
  }

  // ── Toast
  const [toast, setToast] = useState({ visible:false, message:'' });
  function showToast(message){
    setToast({ visible:true, message });
    setTimeout(() => setToast(t => ({ ...t, visible:false })), 2400);
  }

  // ── Activity handlers
  function toggleComplete(id, evt){
    // Capture click position for confetti origin
    const pt = getClickPoint(evt);
    setCompleted(prev => {
      const next = new Set(prev);
      const wasComplete = next.has(id);
      if(wasComplete) next.delete(id);
      else {
        next.add(id);
        const a = ACTIVITIES.find(x => x.id === id);
        showToast(`✓ ${a?.title || 'Activity'} complete`);
        reportEvent('activity_completed', { activity_id:id, activity_title:a?.title });
        if(pt) fireConfetti(pt.x, pt.y, { count: 22, power: 9 });
        // Check milestone after state settles
        setTimeout(() => checkHealthMilestone(), 50);
        if(!pillarsFired.current.action){
          pillarsFired.current.action = true;
          reportMilestone('action_taken', {
            action:'activity_completed', is_major_milestone:true, activity_id:id
          });
          if(!pillarsFired.current.accountability){
            pillarsFired.current.accountability = true;
            reportMilestone('accountability_set', {
              layer:'system_driven', advisor_task_created:true, trigger_action:'activity_completed'
            });
          }
        }
      }
      return next;
    });
  }
  function toggleRemind(id){
    setReminders(prev => {
      const next = new Set(prev);
      if(next.has(id)){ next.delete(id); showToast('Reminder turned off'); }
      else {
        next.add(id);
        const a = ACTIVITIES.find(x => x.id === id);
        showToast(`Reminder set for ${a?.title}`);
        reportEvent('reminder_opted_in', { activity_id:id });
      }
      return next;
    });
  }
  function openResource(item){
    setViewedResources(prev => {
      const next = new Set(prev);
      next.add(item.id || `act-${item.id}`);
      return next;
    });
    // If resource has body content, show modal; otherwise just toast
    if(item.body){
      setResourceModal(item);
    } else {
      showToast(`Opening: ${item.title || item.expanded?.resourceLabel}`);
    }
    reportEvent('resource_opened', { resource_id:item.id, resource_title:item.title });
  }
  function handleContact(kind){
    reportEvent(`contact_${kind}_clicked`, { advisor_email: advisor.email });
    if(!pillarsFired.current.action){
      pillarsFired.current.action = true;
      reportMilestone('action_taken', { action:`contact_${kind}`, is_major_milestone:true });
    }
  }
  function handleCommit({ activityId, date }){
    setCommitted(true);
    showToast('Commitment saved');
    reportMilestone('accountability_set', {
      layer:'self_accountability', activity_id: activityId,
      commit_date: date, self_accountability_opted_in: true
    });
  }

  // ── Setup form → generate shareable URL
  function handleGenerate(form){
    const a = {
      name: form.advisorName, firm: form.advisorFirm, email: form.advisorEmail,
      phone: form.advisorPhone, booking: form.advisorBooking,
      servicePage: form.advisorServicePage
    };
    setAdvisor(a);
    setClientName(form.clientName);
    const params = new URLSearchParams();
    params.set('name', form.advisorName);
    params.set('firm', form.advisorFirm);
    params.set('email', form.advisorEmail);
    if(form.advisorPhone) params.set('phone', form.advisorPhone);
    if(form.advisorBooking) params.set('booking', form.advisorBooking);
    if(form.clientName) params.set('client', form.clientName);
    const base = window.location.href.split('?')[0].split('#')[0];
    setShareUrl(`${base}?${params.toString()}`);
    reportEvent('advisor_setup_completed', { firm: form.advisorFirm });
  }

  // ── Derived stats
  const stats = useMemo(() => {
    let done=0, active=0, upcoming=0, overdue=0;
    ACTIVITIES.forEach(a => {
      if(forceOverdue.has(a.id) && !completed.has(a.id)) { overdue++; return; }
      const s = deriveStatus(a, completed);
      if(s==='complete') done++;
      else if(s==='overdue') overdue++;
      else if(s==='active') active++;
      else upcoming++;
    });
    return { done, active, upcoming, overdue, total: ACTIVITIES.length };
  }, [completed, forceOverdue]);

  const score = useMemo(() => {
    return ACTIVITIES.reduce((sum,a) => sum + (completed.has(a.id) ? a.points : 0), 0);
  }, [completed]);
  const maxScore = useMemo(() => ACTIVITIES.reduce((s,a)=>s+a.points,0), []);

  // ── Overall plan health (0-100)
  const health = useMemo(() => {
    // Activities: % complete, overdue items subtract extra
    const activityDone = ACTIVITIES.filter(a => completed.has(a.id)).length;
    const activityOverdueCount = ACTIVITIES.filter(a => forceOverdue.has(a.id) && !completed.has(a.id)).length;
    const activityPct = (activityDone / ACTIVITIES.length) * 100;
    const activityScore = Math.max(0, activityPct - (activityOverdueCount * 6));

    // Compliance: % complete, overdue items subtract
    const compDone = complianceItems.filter(i => i.completed).length;
    const compOverdue = complianceItems.filter(i => i.overdue && !i.completed).length;
    const compPct = (compDone / complianceItems.length) * 100;
    const compScore = Math.max(0, compPct - (compOverdue * 8));

    // Resources viewed: softer weight
    const resPct = RESOURCES ? Math.min(100, (viewedResources.size / Math.max(1, RESOURCES.length)) * 100) : 0;

    // Coverage: count pillars in-place
    const state = DEMO_STATES[tweaks.demoState] || DEMO_STATES.midyear;
    const coverage = (COVERAGE_BY_STATE && COVERAGE_BY_STATE[tweaks.demoState]) || {};
    const pillars = COVERAGE_PILLARS || [];
    const goodStatuses = ['in-place'];
    const goodPillars = pillars.filter(p => {
      const c = coverage[p.id];
      return c && goodStatuses.includes(c.status);
    }).length;
    const coveragePct = pillars.length ? (goodPillars / pillars.length) * 100 : 0;

    // Weighted: compliance is highest, then activities, then coverage, then resources
    const total = Math.round(
      compScore * 0.35 +
      activityScore * 0.30 +
      coveragePct * 0.25 +
      resPct * 0.10
    );

    let bucket = 'excellent', label = 'Excellent';
    if(total < 40){ bucket = 'behind'; label = 'Behind'; }
    else if(total < 65){ bucket = 'attention'; label = 'Needs attention'; }
    else if(total < 85){ bucket = 'ontrack'; label = 'On track'; }

    // Counts for the strip copy
    const openActivity = ACTIVITIES.length - activityDone;
    const openCompliance = complianceItems.length - compDone;

    return { total, bucket, label, openActivity, openCompliance, activityDone, compDone,
      activityOverdueCount, compOverdue };
  }, [completed, complianceItems, forceOverdue, viewedResources, tweaks.demoState]);

  // Track health transitions for milestone confetti
  const prevHealthRef = useRef(null);
  function checkHealthMilestone(){
    // Defer to next tick so state has settled
    setTimeout(() => {
      const h = healthRef.current;
      const prev = prevHealthRef.current;
      if(prev != null && h != null){
        const thresholds = [25, 50, 75, 100];
        for(const t of thresholds){
          if(prev < t && h >= t){
            // Big burst from center of viewport
            fireConfetti(window.innerWidth / 2, window.innerHeight * 0.35, { big:true, power:14, spread:Math.PI*1.2 });
            showToast(`🎉 Plan health hit ${t}%`);
            break;
          }
        }
      }
      prevHealthRef.current = h;
    }, 120);
  }
  const healthRef = useRef(health.total);
  useEffect(() => { healthRef.current = health.total; }, [health.total]);
  // Initialize prev on mount
  useEffect(() => { if(prevHealthRef.current == null) prevHealthRef.current = health.total; }, []);

  function getClickPoint(evt){
    if(!evt) return null;
    try{
      const t = evt.currentTarget || evt.target;
      if(t && t.getBoundingClientRect){
        const r = t.getBoundingClientRect();
        return { x: r.left + r.width/2, y: r.top + r.height/2 };
      }
      if(evt.clientX != null) return { x: evt.clientX, y: evt.clientY };
    } catch(e){}
    return null;
  }

  const clientFirst = (effectiveClient||'').split('&')[0].trim().split(' ')[0];

  return (
    <React.Fragment>
      <Header clientFirstName={clientFirst}/>
      {setupOpen && (
        <SetupBar onGenerate={(f)=>{ handleGenerate(f); }} shareUrl={shareUrl} onHide={()=>setSetupOpen(false)}/>
      )}
      <Hero advisor={advisor} client={{name:effectiveClient}}
        score={score} maxScore={maxScore}
        progressDisplay={tweaks.progressDisplay}
        variant={tweaks.heroVariant}
        onContact={handleContact}
        stats={stats}/>
      <HealthStrip health={health}/>
      <div className="content-wrap">
        <ActivitySection activities={ACTIVITIES} completed={completed}
          reminders={reminders}
          forceOverdue={forceOverdue}
          overdueDates={overdueDates}
          onToggle={toggleComplete}
          onToggleRemind={toggleRemind}
          onOpenResource={openResource}
          viewMode={tweaks.activityView}/>
        <ComplianceSection compliance={{ items: complianceItems }}
          onToggle={toggleCompliance}
          advisor={advisor}
          onContact={handleContact}/>
        <CoverageMap pillars={COVERAGE_PILLARS}
          coverageByState={COVERAGE_BY_STATE}
          demoState={tweaks.demoState}
          advisor={advisor}
          onContact={handleContact}/>
        <ConversationsSection conversations={CONVERSATIONS} advisor={advisor}
          onContact={handleContact}/>
        <ResourcesSection resources={RESOURCES} topics={RESOURCE_TOPICS}
          viewed={viewedResources} onOpen={openResource}
          advisor={advisor} onContact={handleContact}
          planStatus={tweaks.planStatus || 'ready'}/>
        <PartnerToolsSection advisor={advisor} onContact={handleContact}
          planStatus={tweaks.planStatus || 'ready'}/>
        {tweaks.showAccountability && (
          <AccountabilitySection onCommit={handleCommit} committed={committed}/>
        )}
        <CTABlock advisor={advisor} onContact={handleContact}/>
      </div>
      <SiteFooter/>
      <TweaksPanel open={tweaksOpen} tweaks={tweaks} setTweak={setTweak}
        onClose={()=>setTweaksOpen(false)}/>
      {resourceModal && (
        <ResourceModal resource={resourceModal} onClose={()=>setResourceModal(null)}/>
      )}
      <Toast message={toast.message} visible={toast.visible}/>
    </React.Fragment>
  );
}

function ResourceModal({ resource, onClose }){
  React.useEffect(() => {
    const h = e => { if(e.key === 'Escape') onClose(); };
    window.addEventListener('keydown', h);
    return () => window.removeEventListener('keydown', h);
  }, [onClose]);

  return (
    <div className="resource-modal-overlay" onClick={onClose}>
      <div className="resource-modal-card" onClick={e=>e.stopPropagation()}>
        <button className="resource-modal-close" onClick={onClose} aria-label="Close">×</button>
        <div className="resource-modal-head">
          <span className="resource-modal-icon" style={{color:'var(--accent)',borderColor:'var(--accent)'}}>
            {Icon.doc}
          </span>
          <div>
            <div className="resource-modal-label">{resource.kind}</div>
            <h3 className="resource-modal-title">{resource.title}</h3>
          </div>
        </div>
        <div className="resource-modal-body" dangerouslySetInnerHTML={{__html: resource.body}}></div>
      </div>
    </div>
  );
}

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