<script>
  // The execution layer. Everything else in this app exists to get assets OUT of
  // the probate-bound estate before death. This module is what fires WHEN death
  // happens: verify it via multiple attestors (not a single point of failure or
  // fraud), then generate ready-to-file execution packets for every fast-path
  // instrument already on record — so a family is filing paperwork in days, not
  // waiting on a Shariah Court docket for years.
  //
  // What this can and cannot do, stated plainly:
  //  - CAN: generate the correct claim/transfer paperwork for each covered asset,
  //    pre-filled from the Asset Registry, Hibah, Waqf, and Nomination records.
  //  - CANNOT: itself move money, transfer land title, or force an institution to
  //    act — EPF, the bank, Takaful, and the Land Office are the ones who actually
  //    execute, on their own timelines. This app's job is to remove every reason
  //    for THEM to be slow (no missing paperwork, no ambiguity about who gets what,
  //    no court step required for covered assets) so their part can be done in the
  //    1-2 week window instead of stacking behind a 2-year probate queue.
  import { onMount } from 'svelte';
  import { computeCoverage } from './nonprobate.js';
  import { activeFamilyId, listMyFamilies } from './family.js';
  import { listAssets, listHibahGifts, listNominations, listAllWaqfForFamily, listAttestors, addAttestor as addAttestorDb, updateAttestorName, setAttestorConfirmed, getDeathTrigger, upsertDeathTriggerSetup, updateDeathTriggerField, fireDeathTrigger } from './db.js';
  import { supabase } from './supabaseClient.js';
  import InfoPanel from './InfoPanel.svelte';

  let familyId = $state(null);
  activeFamilyId.subscribe(v => familyId = v);

  let coverage = $state({ rows: [], total: 0, fastTotal: 0, exposedTotal: 0, fastPercent: 0 });
  let myRole = $state(null);
  let executorName = $state('');
  let attestors = $state([]);
  let deathCertRef = $state('');
  let dateOfDeath = $state('');
  let triggered = $state(false);
  let error = $state('');

  async function refresh() {
    if (!familyId) return;
    const [assets, gifts, nominations, waqfDesignations, families] = await Promise.all([
      listAssets(familyId), listHibahGifts(familyId), listNominations(familyId), listAllWaqfForFamily(familyId), listMyFamilies()
    ]);
    const waqfCorpusIds = waqfDesignations.map(w => w.corpus_asset_id).filter(Boolean);
    coverage = computeCoverage({ assets, gifts, nominations, waqfCorpusIds });
    myRole = families.find(f => f.id === familyId)?.role;

    attestors = await listAttestors(familyId);
    // Seed empty attestor rows with real DB rows immediately (not lazily on
    // first blur) — a lazy id meant two different code paths could race to
    // create the same row, and setAttestorConfirmed could end up updating a
    // stale/duplicate id while the visible row kept whichever id resolved last.
    while (attestors.length < 2) {
      const row = await addAttestorDb(familyId, '');
      attestors = [...attestors, { id: row.id, name: '', confirmed: false }];
    }
    const trig = await getDeathTrigger(familyId);
    if (trig) {
      executorName = trig.executor_name || '';
      dateOfDeath = trig.date_of_death || '';
      deathCertRef = trig.death_cert_ref || '';
      triggered = !!trig.triggered;
    }
  }

  onMount(refresh);
  $effect(() => { familyId; refresh(); });

  async function saveExecutorField(column, value) {
    await updateDeathTriggerField(familyId, column, value || null);
  }

  async function addAttestorRow() {
    const row = await addAttestorDb(familyId, '');
    attestors = [...attestors, { id: row.id, name: '', confirmed: false }];
  }

  async function saveAttestorName(a) {
    await updateAttestorName(a.id, a.name);
  }

  async function toggleConfirm(a) {
    a.confirmed = !a.confirmed;
    attestors = [...attestors];
    await setAttestorConfirmed(a.id, a.confirmed);
  }

  const confirmedCount = $derived(attestors.filter(a => a.confirmed && a.name).length);
  const threshold = 2;
  const canTrigger = $derived(confirmedCount >= threshold && deathCertRef && dateOfDeath && myRole === 'owner');

  async function fireTrigger() {
    error = '';
    if (!canTrigger) return;
    try {
      await upsertDeathTriggerSetup(familyId, { executorName, dateOfDeath, deathCertRef });
      await fireDeathTrigger(familyId);
      triggered = true;
    } catch (e) {
      error = 'Only the head of family (owner) can fire the death trigger. ' + (e.message || '');
    }
  }

  async function resetDemo() {
    await supabase.from('nf_death_triggers').update({ triggered: false }).eq('family_id', familyId);
    triggered = false;
  }

  function downloadPacket(row) {
    const lines = [
      'EXECUTION PACKET — NON-PROBATE ASSET TRANSFER',
      `Asset: ${row.asset.description} (${row.asset.type})`,
      `Channel: ${row.channel}`,
      `Value: ${row.ownedValue.toLocaleString()}`,
      `Date of death: ${dateOfDeath}`,
      `Death certificate reference: ${deathCertRef}`,
      `Attestors confirming: ${attestors.filter(a => a.confirmed && a.name).map(a => a.name).join(', ')}`,
      '',
      row.channel === 'hibah'
        ? 'ACTION: This asset was already gifted (Hibah) with completed offer, acceptance,\nand possession prior to death. It is not part of the estate. No probate filing is\nrequired for this asset. Attach the Hibah record and recipient acknowledgment as\nproof of prior transfer if the institution requests confirmation.'
        : row.channel === 'waqf'
        ? 'ACTION: This asset was already dedicated as Waqf prior to death. It is not part\nof the estate. File the waqfiyya deed with the relevant state waqf authority for\nadministrative continuity — this is a registration step, not a probate step.'
        : row.channel === 'epf'
        ? 'ACTION: File an EPF death claim (Borang KWSP 9K or current equivalent) with the\ndeath certificate. EPF pays the nominee directly under EPF Act 1991 s.51 —\nno Letters of Administration required.'
        : row.channel === 'takaful'
        ? 'ACTION: File a death claim with the Takaful/insurance provider. As a nominated\ntrust under Insurance Act 1996 s.166 (or Takaful equivalent), payout goes directly\nto the named beneficiary — no probate required.'
        : row.channel === 'bank-mandate'
        ? 'ACTION: Notify the bank with the death certificate and the death-mandate /\njoint-account documentation on file. Funds release per the mandate terms — this\nis a bank process, not a court process.'
        : row.channel === 'business-continuity'
        ? 'ACTION: Execute the pre-agreed buy-sell provision or partnership continuation\nclause on file. If Takaful-funded, file the Takaful death claim to release the\nbuyout funds. This is a private agreement between co-owners/shareholders, not a\nprobate filing.'
        : row.channel === 'digital-custody'
        ? 'ACTION: File the death claim with the custodial platform\'s own beneficiary\nfeature, or have the named multi-sig co-signer/key-escrow holder execute access\nper the plan on file. This is a platform or private-key process, not a probate\nfiling — and never requires disclosing a seed phrase to this app.'
        : 'ACTION: Contact the trustee/nominee holder to execute the pre-arranged transfer\nunder the trust deed. This is an internal trustee record update, not a probate\nfiling.',
      '',
      'This packet was generated by Nur Falah on a local device. It is a drafting aid;',
      'the receiving institution\'s own claim process still applies. Its purpose is to',
      'remove ambiguity and missing paperwork as a source of delay.'
    ];
    const blob = new Blob([lines.join('\n')], { type: 'text/plain' });
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url; a.download = `execution-packet-${row.asset.description.replace(/\s+/g, '-').toLowerCase()}.txt`; a.click();
    URL.revokeObjectURL(url);
  }
</script>

<div class="module">
  <div class="module-header">
    <h2>Death Trigger &amp; Execution</h2>
    <InfoPanel
      title="Death Trigger & Execution"
      what="This is what actually fires when someone passes away. It can't be triggered by one person alone (to prevent fraud or a mistake) — you need at least two trusted people to confirm the death, plus a death certificate reference. Once confirmed, the app generates ready-to-file paperwork for every asset you've already covered, so your family can start claiming things within days instead of waiting on a court."
      how="Set this up now, while everyone is healthy — name your executor and at least two attestors (people who will confirm the death when it happens). When the time comes, those attestors log in and confirm, someone enters the death certificate number, and the trigger fires — generating a downloadable packet for each covered asset."
      fields={[
        { label: 'Executor', hint: 'The person responsible for carrying out your wishes.' },
        { label: 'Attestors', hint: 'At least two people who will confirm the death actually happened — this is a safety check, not a formality.' },
        { label: 'Date of death & death certificate reference', hint: 'Required before the trigger can fire — this ties everything to an official record.' }
      ]}
    />
  </div>
  <p class="sub">Set up now, fires at death. This is the mechanism that turns "arranged" into "distributed" — target: days, not the ~2-year Faraid/probate route.</p>

  {#if !triggered}
    <div class="setup-card">
      <h3>1. Executor</h3>
      <label class="field"><span>Executor name</span><input type="text" bind:value={executorName} oninput={e => saveExecutorField('executor_name', e.target.value)} /></label>

      <h3>2. Attestors</h3>
      <p class="note">At least {threshold} confirmations plus a death certificate reference are required to fire the trigger — no single person can trigger this alone, and it cannot fire silently.</p>
      {#each attestors as a}
        <div class="attestor-row">
          <input type="text" placeholder="Attestor name" bind:value={a.name} onblur={() => saveAttestorName(a)} />
          <button class="confirm-btn" class:on={a.confirmed} onclick={() => toggleConfirm(a)}>{a.confirmed ? 'Confirmed' : 'Confirm death'}</button>
        </div>
      {/each}
      <button class="btn-secondary" onclick={addAttestorRow}>Add another attestor</button>

      <h3>3. Death record</h3>
      <label class="field"><span>Date of death</span><input type="date" bind:value={dateOfDeath} oninput={e => saveExecutorField('date_of_death', e.target.value)} /></label>
      <label class="field"><span>Death certificate reference number</span><input type="text" bind:value={deathCertRef} oninput={e => saveExecutorField('death_cert_ref', e.target.value)} /></label>

      {#if myRole === 'agent'}
        <div class="agent-restriction">As an estate agent, you can set up everything above — but only the head of family (owner) can fire the trigger. Ask them to review and confirm when the time comes.</div>
      {/if}
      {#if error}<p class="error-text">{error}</p>{/if}

      <div class="trigger-status">
        <span>{confirmedCount} / {threshold} attestor confirmations</span>
        {#if canTrigger}<span class="ready">Ready to trigger</span>{/if}
      </div>

      <button class="btn-danger-solid" disabled={!canTrigger} onclick={fireTrigger}>Fire death trigger — begin execution</button>
    </div>
  {:else}
    <div class="triggered-banner">
      <strong>TRIGGERED.</strong> Death confirmed {dateOfDeath} by {confirmedCount} attestors. Execution packets below are ready for each covered asset.
    </div>

    <div class="coverage-summary">
      <span>{coverage.fastPercent}% of the estate has an execution packet below.</span>
      {#if coverage.exposedTotal > 0}
        <span class="exposed-note">{coverage.exposedTotal.toLocaleString()} has no fast-path coverage and must go through the conventional Faraid/probate process — this was the gap the Coverage Dashboard flagged before death.</span>
      {/if}
    </div>

    {#each coverage.rows.filter(r => r.fast) as r (r.asset.id)}
      <div class="packet-row">
        <div>
          <strong>{r.asset.description}</strong>
          <span class="muted">{r.channel} · {r.ownedValue.toLocaleString()}</span>
        </div>
        <button class="btn-small" onclick={() => downloadPacket(r)}>Download packet</button>
      </div>
    {/each}

    <button class="btn-secondary" onclick={resetDemo}>Reset (testing only)</button>
  {/if}
</div>

<style>
  .module { padding: 4px 0 40px; }
  .module-header { display: flex; align-items: center; margin-bottom: 4px; }
  h2 { font-family: 'DM Serif Display', serif; font-size: 24px; color: #E8E4DC; margin-bottom: 0; }
  .sub { font-size: 13px; color: #8A8478; margin-bottom: 18px; line-height: 1.5; }
  .setup-card { background: rgba(255,255,255,0.03); border-radius: 12px; padding: 16px; }
  .setup-card h3 { font-size: 14px; color: #C9A84C; margin: 16px 0 8px; }
  .setup-card h3:first-child { margin-top: 0; }
  .note { font-size: 11.5px; color: #8A8478; margin-bottom: 10px; line-height: 1.5; }
  .field { display: flex; flex-direction: column; gap: 6px; margin-bottom: 12px; }
  .field span { font-size: 12px; color: #B8B2A6; }
  .field input { background: rgba(255,255,255,0.05); border: 1px solid rgba(201,168,76,0.2); border-radius: 8px; padding: 10px 12px; color: #E8E4DC; font-size: 14px; width: 100%; }
  .attestor-row { display: flex; gap: 8px; margin-bottom: 8px; }
  .attestor-row input { flex: 1; background: rgba(255,255,255,0.05); border: 1px solid rgba(201,168,76,0.2); border-radius: 8px; padding: 8px 10px; color: #E8E4DC; font-size: 13px; }
  .confirm-btn { padding: 8px 12px; border-radius: 8px; border: 1px solid rgba(239,68,68,0.3); background: rgba(239,68,68,0.1); color: #EF4444; font-size: 11px; cursor: pointer; white-space: nowrap; }
  .confirm-btn.on { border-color: rgba(46,204,113,0.4); background: rgba(46,204,113,0.15); color: #2ECC71; }
  .btn-secondary { width: 100%; padding: 10px; border-radius: 8px; border: none; background: rgba(255,255,255,0.08); color: #E8E4DC; font-weight: 600; cursor: pointer; margin: 8px 0 4px; font-size: 13px; }
  .trigger-status { display: flex; justify-content: space-between; align-items: center; font-size: 12px; color: #B8B2A6; margin: 16px 0 10px; }
  .ready { color: #2ECC71; font-weight: 600; }
  .agent-restriction { font-size: 12px; color: #C9A84C; background: rgba(201,168,76,0.08); border-radius: 8px; padding: 10px 12px; margin: 10px 0; line-height: 1.5; }
  .error-text { font-size: 12px; color: #EF4444; margin: 8px 0; }
  .btn-danger-solid { width: 100%; padding: 14px; border-radius: 8px; border: none; background: #EF4444; color: white; font-weight: 700; cursor: pointer; }
  .btn-danger-solid:disabled { opacity: 0.3; cursor: not-allowed; }

  .triggered-banner { background: rgba(239,68,68,0.1); border: 1px solid rgba(239,68,68,0.3); border-radius: 10px; padding: 14px; font-size: 13px; color: #E8E4DC; margin-bottom: 14px; line-height: 1.5; }
  .coverage-summary { background: rgba(255,255,255,0.03); border-radius: 10px; padding: 12px; margin-bottom: 14px; display: flex; flex-direction: column; gap: 6px; font-size: 12px; color: #B8B2A6; }
  .exposed-note { color: #EF4444; }
  .packet-row { display: flex; justify-content: space-between; align-items: center; padding: 12px; background: rgba(46,204,113,0.05); border-radius: 10px; margin-bottom: 8px; font-size: 13px; color: #E8E4DC; }
  .muted { display: block; color: #8A8478; font-size: 11px; margin-top: 2px; }
  .btn-small { background: rgba(46,204,113,0.15); color: #2ECC71; border: none; border-radius: 8px; padding: 8px 12px; font-size: 12px; cursor: pointer; font-weight: 600; }
</style>
