// dashboard-trigger-section-phase-4-manual.js — extracted verbatim from dashboard.js (pure move).

// ── Trigger section (Phase 4 — manual / schedule / event) ──────────

let _composerEventSources = null;

async function _ensureEventSources() {
  if (_composerEventSources) return _composerEventSources;
  const r = await api("composition-event-sources").catch(() => null);
  _composerEventSources = r?.sources || [];
  return _composerEventSources;
}

async function _composerTriggerSection(draft) {
  const wrap = el("div", {
    style:
      "margin-bottom: 14px; padding: 10px 12px; background: #0a0a0f; border: 1px solid var(--border); border-radius: 6px;",
  });
  wrap.appendChild(
    el("div", { class: "muted", style: "font-size: 11px; margin-bottom: 6px;" }, "Trigger"),
  );

  if (!draft.trigger) draft.trigger = { type: "manual" };

  // Three-pill segmented control
  const segRow = el("div", { class: "row", style: "gap: 4px; margin-bottom: 8px;" });
  const triggers = [
    { id: "manual", label: "▶ Manual" },
    { id: "schedule", label: "⏰ Schedule" },
    { id: "event", label: "Event" },
  ];
  const detail = el("div", {});

  const renderDetail = async () => {
    detail.innerHTML = "";
    if (draft.trigger.type === "schedule" || draft.trigger.type === "schedule_simple") {
      detail.appendChild(await _composerScheduleDetail(draft));
    } else if (draft.trigger.type === "event") {
      detail.appendChild(await _composerEventDetail(draft));
    } else {
      detail.appendChild(
        el(
          "div",
          { class: "muted", style: "font-size: 11px;" },
          "Manual trigger — fires only when you click Run now.",
        ),
      );
    }
  };

  const renderSeg = () => {
    segRow.innerHTML = "";
    for (const t of triggers) {
      const isOn =
        draft.trigger.type === t.id ||
        (t.id === "schedule" && draft.trigger.type === "schedule_simple");
      segRow.appendChild(
        el(
          "button",
          {
            class: `btn btn-tiny ${isOn ? "btn-primary" : "btn-secondary"}`,
            type: "button",
            onclick: async () => {
              if (t.id === "manual") draft.trigger = { type: "manual" };
              // Phase 33: default new schedule choices to easy mode (schedule_simple
              // sugar from Phase 27). Users can switch to raw cron via the toggle
              // at the top of the schedule detail.
              if (t.id === "schedule")
                draft.trigger = {
                  type: "schedule_simple",
                  every: "day",
                  at: "09:00",
                  timezone: "UTC",
                };
              if (t.id === "event")
                draft.trigger = { type: "event", source: "li_connection_request" };
              renderSeg();
              await renderDetail();
            },
          },
          t.label,
        ),
      );
    }
  };

  renderSeg();
  await renderDetail();
  wrap.appendChild(segRow);
  wrap.appendChild(detail);
  return wrap;
}

async function _composerScheduleDetail(draft) {
  const wrap = el("div", {});

  // Phase 33: schedule mode toggle — Easy (schedule_simple sugar from
  // Phase 27) vs Cron expression (full power, raw 5-field). Easy mode
  // covers "every day/week/hour/minute" patterns most users actually use.
  const isSimple = draft.trigger.type === "schedule_simple";
  const modeRow = el("div", { class: "row", style: "gap: 6px; margin-bottom: 10px;" });
  const easyBtn = el(
    "button",
    {
      class: `btn btn-tiny ${isSimple ? "btn-primary" : "btn-secondary"}`,
      type: "button",
    },
    "Easy",
  );
  const cronBtn = el(
    "button",
    {
      class: `btn btn-tiny ${!isSimple ? "btn-primary" : "btn-secondary"}`,
      type: "button",
    },
    "Cron expression",
  );
  modeRow.appendChild(easyBtn);
  modeRow.appendChild(cronBtn);
  wrap.appendChild(modeRow);

  const detail = el("div", {});
  wrap.appendChild(detail);

  const renderMode = async () => {
    detail.innerHTML = "";
    if (draft.trigger.type === "schedule_simple") {
      detail.appendChild(_composerScheduleSimpleDetail(draft));
    } else {
      detail.appendChild(await _composerScheduleCronDetail(draft));
    }
    easyBtn.className = `btn btn-tiny ${draft.trigger.type === "schedule_simple" ? "btn-primary" : "btn-secondary"}`;
    cronBtn.className = `btn btn-tiny ${draft.trigger.type === "schedule" ? "btn-primary" : "btn-secondary"}`;
  };

  easyBtn.onclick = async () => {
    if (draft.trigger.type === "schedule_simple") return;
    draft.trigger = {
      type: "schedule_simple",
      every: "day",
      at: "09:00",
      timezone: draft.trigger.timezone || "UTC",
    };
    await renderMode();
  };
  cronBtn.onclick = async () => {
    if (draft.trigger.type === "schedule") return;
    draft.trigger = {
      type: "schedule",
      cron: draft.trigger.cron || "0 9 * * *",
      timezone: draft.trigger.timezone || "UTC",
    };
    await renderMode();
  };

  await renderMode();
  return wrap;
}

/**
 * Phase 33 — Easy schedule mode (Phase 27 schedule_simple sugar).
 * Covers `every: day | week | hour | minute_of_hour` with at-time / step-minutes
 * sub-controls. Maps cleanly to schedule_simple's body shape.
 */
function _composerScheduleSimpleDetail(draft) {
  const wrap = el("div", {});
  draft.trigger.every = draft.trigger.every || "day";
  draft.trigger.timezone = draft.trigger.timezone || "UTC";

  // every: day | week | hour | minute_of_hour
  const everySelect = el("select", { class: "wizard-input", style: "max-width: 200px;" }, [
    el("option", { value: "day" }, "Every day"),
    el("option", { value: "week" }, "Every week (Mondays)"),
    el("option", { value: "hour" }, "Every hour"),
    el("option", { value: "minute_of_hour" }, "Every N minutes"),
  ]);
  everySelect.value = draft.trigger.every;

  // For day/week: at = "HH:MM"
  const atInput = el("input", {
    type: "time",
    class: "wizard-input",
    value: draft.trigger.at || "09:00",
    style: "width: 120px;",
  });
  // For hour: at_minute = 0-59
  const atMinuteInput = el("input", {
    type: "number",
    class: "wizard-input",
    min: "0",
    max: "59",
    value: String(draft.trigger.at_minute ?? 0),
    style: "width: 70px;",
  });
  // For minute_of_hour: step_minutes = 1-59
  const stepMinutesInput = el("input", {
    type: "number",
    class: "wizard-input",
    min: "1",
    max: "59",
    value: String(draft.trigger.step_minutes ?? 15),
    style: "width: 70px;",
  });

  const tzInput = el("input", {
    type: "text",
    class: "wizard-input",
    value: draft.trigger.timezone,
    placeholder: "UTC",
    style: "max-width: 200px; font-size: 12px;",
  });

  const weekdaysOnlyInput = el("input", {
    type: "checkbox",
    checked: draft.trigger.weekdays_only ? "checked" : null,
  });

  const subControls = el("div", {
    class: "row",
    style: "gap: 8px; margin-top: 8px; align-items: center; font-size: 11px; flex-wrap: wrap;",
  });
  const previewLine = el(
    "div",
    { class: "muted", style: "font-size: 11px; margin-top: 6px;" },
    "Next runs: —",
  );

  const refreshPreview = async () => {
    previewLine.textContent = "Computing…";
    // Build cron-equivalent so we can hit the existing /cron-preview API
    const t = draft.trigger;
    const dow = t.weekdays_only ? "1-5" : "*";
    let expr = "";
    if (t.every === "minute_of_hour") {
      const step = Math.max(1, Math.min(59, Number(t.step_minutes) || 15));
      expr = `*/${step} * * * ${dow}`;
    } else if (t.every === "hour") {
      const m = Math.max(0, Math.min(59, Number(t.at_minute) || 0));
      expr = `${m} * * * ${dow}`;
    } else {
      const [h, m] = String(t.at || "09:00")
        .split(":")
        .map((s) => parseInt(s, 10));
      if (t.every === "week") expr = `${m} ${h} * * 1`;
      else expr = `${m} ${h} * * ${dow}`;
    }
    const r = await api("composition-cron-preview", { expr, n: 3 }).catch(() => null);
    if (!r || !Array.isArray(r.firings) || r.firings.length === 0) {
      previewLine.textContent = `Equivalent cron: ${expr} — no firings in next 7 days`;
      return;
    }
    const lines = r.firings.map((iso) => new Date(iso).toLocaleString());
    previewLine.textContent = `Equivalent cron: ${expr} · Next: ${lines.join(" · ")}`;
  };

  const renderSubControls = () => {
    subControls.innerHTML = "";
    const every = draft.trigger.every;
    if (every === "day" || every === "week") {
      subControls.appendChild(el("span", { class: "muted" }, "at"));
      subControls.appendChild(atInput);
    }
    if (every === "hour") {
      subControls.appendChild(el("span", { class: "muted" }, "at minute"));
      subControls.appendChild(atMinuteInput);
    }
    if (every === "minute_of_hour") {
      subControls.appendChild(el("span", { class: "muted" }, "every"));
      subControls.appendChild(stepMinutesInput);
      subControls.appendChild(el("span", { class: "muted" }, "minutes"));
    }
    if (every !== "week") {
      subControls.appendChild(
        el("label", { style: "cursor: pointer; margin-left: 12px;" }, [
          weekdaysOnlyInput,
          " weekdays only",
        ]),
      );
    }
    subControls.appendChild(el("span", { class: "muted", style: "margin-left: 12px;" }, "TZ"));
    subControls.appendChild(tzInput);
    refreshPreview();
  };

  everySelect.addEventListener("change", () => {
    const next = everySelect.value;
    draft.trigger.every = next;
    // Clean fields irrelevant to the new mode
    if (next !== "minute_of_hour") delete draft.trigger.step_minutes;
    if (next !== "hour") delete draft.trigger.at_minute;
    if (next !== "day" && next !== "week") delete draft.trigger.at;
    if (next === "minute_of_hour")
      draft.trigger.step_minutes = Number(stepMinutesInput.value) || 15;
    if (next === "hour") draft.trigger.at_minute = Number(atMinuteInput.value) || 0;
    if (next === "day" || next === "week") draft.trigger.at = atInput.value || "09:00";
    renderSubControls();
  });
  atInput.addEventListener("change", () => {
    draft.trigger.at = atInput.value;
    refreshPreview();
  });
  atMinuteInput.addEventListener("change", () => {
    draft.trigger.at_minute = Number(atMinuteInput.value) || 0;
    refreshPreview();
  });
  stepMinutesInput.addEventListener("change", () => {
    draft.trigger.step_minutes = Number(stepMinutesInput.value) || 15;
    refreshPreview();
  });
  tzInput.addEventListener("change", () => {
    draft.trigger.timezone = tzInput.value;
  });
  weekdaysOnlyInput.addEventListener("change", () => {
    if (weekdaysOnlyInput.checked) draft.trigger.weekdays_only = true;
    else delete draft.trigger.weekdays_only;
    refreshPreview();
  });

  wrap.appendChild(
    el("div", { class: "row", style: "gap: 8px; align-items: center;" }, [
      el("span", { class: "muted", style: "font-size: 11px;" }, "Frequency:"),
      everySelect,
    ]),
  );
  wrap.appendChild(subControls);
  wrap.appendChild(previewLine);
  renderSubControls();
  return wrap;
}

async function _composerScheduleCronDetail(draft) {
  const wrap = el("div", {});
  draft.trigger.cron = draft.trigger.cron || "0 9 * * *";
  draft.trigger.timezone = draft.trigger.timezone || "UTC";

  const cronInput = el("input", {
    type: "text",
    class: "wizard-input",
    value: draft.trigger.cron,
    placeholder: "0 9 * * * (every day at 09:00)",
    style: "max-width: 240px; font-family: monospace; font-size: 12px;",
  });
  const tzInput = el("input", {
    type: "text",
    class: "wizard-input",
    value: draft.trigger.timezone,
    placeholder: "UTC",
    style: "max-width: 200px; font-size: 12px;",
  });

  const previewLine = el(
    "div",
    { class: "muted", style: "font-size: 11px; margin-top: 6px;" },
    "Next runs: —",
  );

  const refreshPreview = async () => {
    previewLine.textContent = "Computing…";
    const r = await api("composition-cron-preview", { expr: cronInput.value, n: 3 }).catch(
      () => null,
    );
    if (!r || !Array.isArray(r.firings) || r.firings.length === 0) {
      previewLine.textContent = "Invalid cron or no firings in next 7 days.";
      return;
    }
    const lines = r.firings.map((iso) => new Date(iso).toLocaleString());
    previewLine.textContent = `Next runs: ${lines.join(" · ")}`;
  };

  cronInput.addEventListener("change", () => {
    draft.trigger.cron = cronInput.value;
    refreshPreview();
  });
  tzInput.addEventListener("change", () => {
    draft.trigger.timezone = tzInput.value;
  });

  // Quick presets
  const presets = [
    { label: "Daily 9am", expr: "0 9 * * *" },
    { label: "Hourly", expr: "0 * * * *" },
    { label: "Every 30 min", expr: "*/30 * * * *" },
    { label: "Mon 9am", expr: "0 9 * * 1" },
    { label: "Weekdays 9am", expr: "0 9 * * 1-5" },
  ];
  const presetRow = el(
    "div",
    { class: "row", style: "gap: 4px; margin-top: 6px; flex-wrap: wrap;" },
    presets.map((p) =>
      el(
        "button",
        {
          class: "btn btn-tiny btn-secondary",
          type: "button",
          onclick: () => {
            cronInput.value = p.expr;
            draft.trigger.cron = p.expr;
            refreshPreview();
          },
        },
        p.label,
      ),
    ),
  );

  wrap.appendChild(
    el("div", { class: "row", style: "gap: 8px; align-items: center; flex-wrap: wrap;" }, [
      el("span", { class: "muted", style: "font-size: 11px;" }, "Cron:"),
      cronInput,
      el("span", { class: "muted", style: "font-size: 11px;" }, "TZ:"),
      tzInput,
    ]),
  );
  wrap.appendChild(presetRow);
  wrap.appendChild(previewLine);

  refreshPreview();
  return wrap;
}

async function _composerEventDetail(draft) {
  const wrap = el("div", {});
  const sources = await _ensureEventSources();
  draft.trigger.source = draft.trigger.source || sources[0]?.id || "li_connection_request";

  // Phase 33: group sources by family (inbound / lifecycle / engagement /
  // intelligence) when surfaced. Falls back to flat list if API didn't
  // supply families.
  const familyOrder = ["inbound", "lifecycle", "engagement", "intelligence"];
  const sourceSelect = el("select", { class: "wizard-input", style: "max-width: 360px;" });
  const grouped = sources.reduce((acc, s) => {
    const fam = s.family || "other";
    (acc[fam] ||= []).push(s);
    return acc;
  }, {});
  const familiesPresent = Object.keys(grouped).filter((f) => grouped[f].length > 0);
  if (familiesPresent.length > 1) {
    for (const fam of [
      ...familyOrder,
      ...familiesPresent.filter((f) => !familyOrder.includes(f)),
    ]) {
      if (!grouped[fam]) continue;
      const optGroup = el("optgroup", { label: fam.charAt(0).toUpperCase() + fam.slice(1) });
      for (const s of grouped[fam]) {
        optGroup.appendChild(
          el("option", { value: s.id }, `${s.label}${s.platform ? ` (${s.platform})` : ""}`),
        );
      }
      sourceSelect.appendChild(optGroup);
    }
  } else {
    for (const s of sources) {
      sourceSelect.appendChild(
        el("option", { value: s.id }, `${s.label}${s.platform ? ` (${s.platform})` : ""}`),
      );
    }
  }
  sourceSelect.value = draft.trigger.source;

  const platformBanner = el("div", { class: "muted", style: "font-size: 11px; margin-top: 6px;" });
  const filterPanel = el("div", { style: "margin-top: 10px;" });

  const refreshBanner = () => {
    const cur = sources.find((s) => s.id === draft.trigger.source);
    if (cur?.platform) {
      platformBanner.textContent = `Channel auto-locks to ${cur.platform}. The audience will be the contact who triggered the event.`;
    } else {
      platformBanner.textContent = `Cross-platform — works on any channel. Use audience source "Whoever triggered this" if you want the event subject.`;
    }
  };

  /**
   * Phase 33: per-source filter editor. Backend Phase 22-28 stores filters
   * on `trigger.filter` as a free-shape object (different per source). The
   * wizard surfaces known filter fields explicitly per source; other
   * sources show a generic JSON editor as fallback.
   */
  const renderFilterPanel = () => {
    filterPanel.innerHTML = "";
    if (!draft.trigger.filter) draft.trigger.filter = {};
    const filter = draft.trigger.filter;
    const source = draft.trigger.source;

    const filterTitle = el(
      "div",
      { style: "font-size: 11px; font-weight: 500; margin-bottom: 6px;" },
      "Filter",
    );
    const filterHint = el("div", {
      class: "muted",
      style: "font-size: 10px; margin-bottom: 8px; line-height: 1.5;",
    });

    // Known shapes per source
    if (source === "tg_group_message") {
      filterHint.textContent =
        "Restrict the trigger to messages from a specific Telegram group. Leave blank to match any group.";
      const chatInput = el("input", {
        type: "text",
        class: "wizard-input",
        value: filter.group_chat_id || "",
        placeholder: "-100123456789",
        style: "width: 220px;",
      });
      chatInput.addEventListener("change", () => {
        const v = chatInput.value.trim();
        if (v) filter.group_chat_id = v;
        else delete filter.group_chat_id;
        if (Object.keys(filter).length === 0) delete draft.trigger.filter;
      });
      filterPanel.appendChild(filterTitle);
      filterPanel.appendChild(filterHint);
      filterPanel.appendChild(
        el("div", { class: "row", style: "gap: 8px; align-items: center; font-size: 11px;" }, [
          el("span", { class: "muted" }, "Group chat ID:"),
          chatInput,
        ]),
      );
    } else if (
      source === "tg_dm_received" ||
      source === "li_dm_received" ||
      source === "x_dm_received"
    ) {
      filterHint.textContent =
        "Restrict to a specific account that received the DM. Leave blank to match any of your accounts.";
      const acctInput = el("input", {
        type: "text",
        class: "wizard-input",
        value: filter.account_id || "",
        placeholder: "account id (numeric or username)",
        style: "width: 220px;",
      });
      acctInput.addEventListener("change", () => {
        const v = acctInput.value.trim();
        if (v) filter.account_id = v;
        else delete filter.account_id;
        if (Object.keys(filter).length === 0) delete draft.trigger.filter;
      });
      filterPanel.appendChild(filterTitle);
      filterPanel.appendChild(filterHint);
      filterPanel.appendChild(
        el("div", { class: "row", style: "gap: 8px; align-items: center; font-size: 11px;" }, [
          el("span", { class: "muted" }, "Account:"),
          acctInput,
        ]),
      );
    } else if (source === "composition_run_completed") {
      filterHint.textContent =
        "Required: source composition ID — fires when that composition's run completes. Pair with a prior_run_* audience resolver to inherit contacts.";
      const compInput = el("input", {
        type: "number",
        class: "wizard-input",
        min: "1",
        value: filter.composition_id || "",
        placeholder: "composition #",
        style: "width: 140px;",
      });
      compInput.addEventListener("change", () => {
        const v = parseInt(compInput.value, 10);
        if (Number.isFinite(v) && v > 0) filter.composition_id = v;
        else delete filter.composition_id;
        if (Object.keys(filter).length === 0) delete draft.trigger.filter;
      });
      filterPanel.appendChild(filterTitle);
      filterPanel.appendChild(filterHint);
      filterPanel.appendChild(
        el("div", { class: "row", style: "gap: 8px; align-items: center; font-size: 11px;" }, [
          el("span", { class: "muted" }, "Source composition ID:"),
          compInput,
        ]),
      );
    } else if (source === "signal_match") {
      filterHint.textContent =
        "Optional: only fire on signals from specific platforms or above a confidence threshold.";
      const platformInput = el("input", {
        type: "text",
        class: "wizard-input",
        value: Array.isArray(filter.platforms)
          ? filter.platforms.join(",")
          : filter.platforms || "",
        placeholder: "twitter, linkedin, reddit, hackernews",
        style: "width: 280px;",
      });
      platformInput.addEventListener("change", () => {
        const list = platformInput.value
          .split(",")
          .map((s) => s.trim().toLowerCase())
          .filter(Boolean);
        if (list.length > 0) filter.platforms = list;
        else delete filter.platforms;
        if (Object.keys(filter).length === 0) delete draft.trigger.filter;
      });
      const confInput = el("input", {
        type: "number",
        class: "wizard-input",
        min: "0",
        max: "1",
        step: "0.1",
        value: filter.min_confidence || "",
        placeholder: "0.7",
        style: "width: 80px;",
      });
      confInput.addEventListener("change", () => {
        const v = parseFloat(confInput.value);
        if (Number.isFinite(v) && v > 0) filter.min_confidence = v;
        else delete filter.min_confidence;
        if (Object.keys(filter).length === 0) delete draft.trigger.filter;
      });
      filterPanel.appendChild(filterTitle);
      filterPanel.appendChild(filterHint);
      filterPanel.appendChild(
        el(
          "div",
          {
            class: "row",
            style: "gap: 8px; align-items: center; font-size: 11px; margin-bottom: 6px;",
          },
          [el("span", { class: "muted", style: "min-width: 100px;" }, "Platforms:"), platformInput],
        ),
      );
      filterPanel.appendChild(
        el("div", { class: "row", style: "gap: 8px; align-items: center; font-size: 11px;" }, [
          el("span", { class: "muted", style: "min-width: 100px;" }, "Min confidence:"),
          confInput,
        ]),
      );
    } else {
      // Fallback: free-text JSON editor for unknown shapes
      filterHint.textContent =
        "Free-text JSON filter (advanced — backend semantics depend on the event source).";
      const jsonInput = el(
        "textarea",
        {
          class: "wizard-textarea",
          placeholder: '{ "key": "value" }',
          style:
            "width: 100%; max-width: 400px; min-height: 60px; font-family: monospace; font-size: 11px;",
        },
        JSON.stringify(filter, null, 2),
      );
      jsonInput.addEventListener("change", () => {
        try {
          const parsed = JSON.parse(jsonInput.value || "{}");
          if (parsed && typeof parsed === "object") {
            draft.trigger.filter = parsed;
            if (Object.keys(parsed).length === 0) delete draft.trigger.filter;
          }
        } catch {
          toast("Invalid JSON — leaving filter unchanged", "err");
        }
      });
      filterPanel.appendChild(filterTitle);
      filterPanel.appendChild(filterHint);
      filterPanel.appendChild(jsonInput);
    }
  };

  sourceSelect.addEventListener("change", () => {
    draft.trigger.source = sourceSelect.value;
    // Reset filter when source changes — filter shapes don't transfer
    delete draft.trigger.filter;
    refreshBanner();
    renderFilterPanel();
  });

  // Helper hint to use inbound_event_subject as audience
  const audHint = el(
    "button",
    {
      class: "btn btn-tiny btn-secondary",
      type: "button",
      style: "margin-top: 8px;",
      onclick: () => {
        const ar = draft.audience.resolvers || [];
        if (!ar.some((r) => r.type === "inbound_event_subject")) {
          ar.push({ type: "inbound_event_subject" });
          draft.audience.resolvers = ar;
          toast("Added 'inbound_event_subject' to audience — refresh to see it.", "ok");
        } else {
          toast("Already in audience.", "ok");
        }
      },
    },
    "+ Use event subject as audience",
  );

  wrap.appendChild(
    el("div", { class: "row", style: "gap: 8px; align-items: center;" }, [
      el("span", { class: "muted", style: "font-size: 11px;" }, "Event source:"),
      sourceSelect,
    ]),
  );
  wrap.appendChild(platformBanner);
  wrap.appendChild(filterPanel);
  wrap.appendChild(audHint);
  refreshBanner();
  renderFilterPanel();
  return wrap;
}
