/* Wa by Elivate — Automation builder (node/flow canvas) */

function FlowNode({ step, icon, tone, title, value, active, dim, onClick }) {
  const I = Icons[icon];
  return (
    <button className={"flow-node" + (active ? " active" : "") + (dim ? " dim" : "")} onClick={onClick}>
      <div className="fn-step">{step}</div>
      <div className="fn-head">
        <span className={"fn-ic " + tone}><I size={18} /></span>
      </div>
      <div className="fn-title">{title}</div>
      <div className="fn-value">{value}</div>
    </button>
  );
}

function Connector({ active }) {
  return (
    <div className="connector">
      <svg width="56" height="56" viewBox="0 0 56 56" fill="none">
        <path d="M2 28 H54" stroke={active ? "var(--brand)" : "var(--border-strong)"} strokeWidth="2" strokeDasharray="1 6" strokeLinecap="round" className={active ? "flow-dash" : ""} />
        <path d="M48 22 L54 28 L48 34" stroke={active ? "var(--brand)" : "var(--text-4)"} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
      </svg>
    </div>
  );
}

// --- Inspector control primitives ---
function RadioCards({ options, value, onChange }) {
  return (
    <div className="radio-cards">
      {options.map((o) => {
        const I = o.icon ? Icons[o.icon] : null;
        return (
          <button key={o.value} className={"radio-card" + (value === o.value ? " on" : "")} onClick={() => onChange(o.value)}>
            {I && <span className="rc-ic"><I size={16} /></span>}
            <span className="rc-label">{o.label}</span>
            <span className="rc-check">{value === o.value && <Icons.check size={13} />}</span>
          </button>
        );
      })}
    </div>
  );
}

const WEEKDAYS = [
  ["0", "Sun"],
  ["1", "Mon"],
  ["2", "Tue"],
  ["3", "Wed"],
  ["4", "Thu"],
  ["5", "Fri"],
  ["6", "Sat"],
];

const DEFAULT_SCHEDULE = {
  mode: "daily",
  date: new Date().toISOString().slice(0, 10),
  time: "09:00",
  startTime: "06:00",
  endTime: "01:00",
  weekday: "1",
  weekdays: ["1", "2", "3", "4", "5"],
  dayOfMonth: 1,
  timezone: "Africa/Lagos",
};

const QUOTE_PROMPT_TEMPLATE = `Generate exactly one fresh quote or short book/podcast-style snippet for the WhatsApp group.

Required output format:
Complex, Interesting, Weird Topic

"Quote body or short book/podcast-style snippet"

- Author

Rules:
- The topic line must be 4 words max.
- Output exactly 3 visible lines separated by blank lines.
- Quote/snippet must be wrapped in double quotes.
- Author line must start with "- ".
- Do not repeat or closely paraphrase any output from the repeat-memory window.
- Prefer original wording. If the line is original, use "- Original".
- If referencing a real author/source, do not invent attribution.
- No hashtags, intro, explanation, labels, or extra text.`;

function BuilderScreen({ initial, onClose, go }) {
  const { TRIGGERS, MATCH_MODES, SCOPES, ACTIONS, summarize } = window.RuleMeta;
  const [groups, setGroups] = React.useState([]);
  const [groupsError, setGroupsError] = React.useState("");
  const blank = { id: null, name: "", enabled: true, trigger: { type: "message", cron: "", schedule: { ...DEFAULT_SCHEDULE } }, match: { mode: "contains", keyword: "", caseSensitive: false }, scope: { type: "dm", groupId: null, groupName: null }, action: { type: "reply", message: "", targetGroupId: null, instructions: "", model: "", repeatWindowDays: 7 } };
  const [rule, setRule] = React.useState(() => initial ? JSON.parse(JSON.stringify(initial)) : blank);
  const [saving, setSaving] = React.useState(false);
  const [testing, setTesting] = React.useState(false);
  const [testOutput, setTestOutput] = React.useState("");
  const [testError, setTestError] = React.useState("");
  const [error, setError] = React.useState("");
  const isMsg = rule.trigger.type === "message";
  const steps = isMsg ? ["trigger", "match", "scope", "action"] : ["trigger", "scope", "action"];
  const [sel, setSel] = React.useState("trigger");

  React.useEffect(() => {
    window.WaApi.groups().then(setGroups).catch((err) => setGroupsError(err.message));
  }, []);

  const up = (patch) => setRule((r) => ({ ...r, ...patch }));
  const upT = (p) => setRule((r) => ({ ...r, trigger: { ...r.trigger, ...p } }));
  const upSchedule = (p) => setRule((r) => {
    const schedule = { ...DEFAULT_SCHEDULE, ...(r.trigger.schedule || {}), ...p };
    return { ...r, trigger: { ...r.trigger, schedule, cron: buildCron(schedule) } };
  });
  const upM = (p) => setRule((r) => ({ ...r, match: { ...r.match, ...p } }));
  const upS = (p) => setRule((r) => ({ ...r, scope: { ...r.scope, ...p } }));
  const upA = (p) => setRule((r) => ({ ...r, action: { ...r.action, ...p } }));
  const setTriggerType = (type) => setRule((r) => {
    if (type !== "schedule") return { ...r, trigger: { ...r.trigger, type } };
    const schedule = { ...DEFAULT_SCHEDULE, ...(r.trigger.schedule || {}) };
    const action = ["reply", "remove_sender"].includes(r.action.type)
      ? { ...r.action, type: "send_group" }
      : r.action;
    return { ...r, trigger: { ...r.trigger, type, schedule, cron: r.trigger.cron || buildCron(schedule) }, scope: { ...r.scope, type: "any" }, action };
  });

  React.useEffect(() => { if (!isMsg && sel === "match") setSel("trigger"); }, [isMsg]);

  // Center the selected node in the canvas viewport
  const scrollRef = React.useRef(null);
  React.useEffect(() => {
    const sc = scrollRef.current; if (!sc) return;
    const el = sc.querySelector(".flow-node.active"); if (!el) return;
    const er = el.getBoundingClientRect(), cr = sc.getBoundingClientRect();
    sc.scrollTo({ left: Math.max(0, sc.scrollLeft + (er.left - cr.left) - (cr.width - er.width) / 2), behavior: "smooth" });
  }, [sel, isMsg]);

  // node display values
  const T = TRIGGERS[rule.trigger.type];
  const A = ACTIONS[rule.action.type];
  const matchVal = rule.match.mode === "any" ? "Any message" : `${MATCH_MODES[rule.match.mode].label} “${rule.match.keyword || "…"}”`;
  const scopeVal = rule.scope.type === "group" ? (rule.scope.groupName || "Pick group…") : SCOPES[rule.scope.type].label;
  const actionVal = (rule.action.type === "reply" || rule.action.type === "send_group") ? (rule.action.message ? `“${rule.action.message.slice(0, 22)}${rule.action.message.length > 22 ? "…" : ""}”` : "Add message…") : A.label;
  const scheduleText = scheduleLabel(rule.trigger.schedule, rule.trigger.cron);

  const save = async () => {
    const validation = validateRule(rule);
    if (validation) {
      setError(validation);
      return;
    }
    setSaving(true);
    setError("");
    try {
      if (rule.id) await window.WaApi.updateAutomation(rule.id, rule);
      else await window.WaApi.createAutomation(rule);
      onClose();
    } catch (err) {
      setError(err.message);
    } finally {
      setSaving(false);
    }
  };

  const test = async () => {
    setTesting(true);
    setError("");
    setTestError("");
    setTestOutput("");
    try {
      const result = await window.WaApi.testAutomation(rule);
      setTestOutput(result.output || "The test ran, but there was no output.");
      setSel("action");
    } catch (err) {
      setTestError(err.message);
      setSel("action");
    } finally {
      setTesting(false);
    }
  };

  return (
    <div className="builder">
      <div className="builder-bar">
        <button className="btn ghost sm" onClick={onClose}><Icons.chevron size={15} style={{ transform: "rotate(180deg)" }} /> Back</button>
        <input className="builder-name" placeholder="Untitled automation" value={rule.name} onChange={(e) => up({ name: e.target.value })} />
        <div className="topbar-spacer"></div>
        <div className="tag" style={{ marginRight: 4 }}><span className={"dot " + (rule.enabled ? "green" : "amber")}></span>{rule.enabled ? "Will be active" : "Saved as paused"}</div>
        <button className="btn ghost sm" onClick={test} disabled={testing}><Icons.play size={14} /> {testing ? "Testing..." : "Test"}</button>
        <button className="btn ghost sm" onClick={onClose}>Discard</button>
        <button className="btn primary sm" onClick={save} disabled={saving}><Icons.check size={15} /> {saving ? "Saving..." : "Save automation"}</button>
      </div>

      <div className="builder-body">
        <div className="canvas">
          <div className="canvas-scroll" ref={scrollRef}>
            <div className="flow-row">
              <FlowNode step="Trigger" icon={T.icon} tone={T.tone} title={T.label} value={rule.trigger.type === "schedule" ? scheduleText : "When this happens"} active={sel === "trigger"} onClick={() => setSel("trigger")} />
              <Connector active />
              {isMsg && <><FlowNode step="Match" icon="filter" tone="brand" title={MATCH_MODES[rule.match.mode].label} value={matchVal} active={sel === "match"} onClick={() => setSel("match")} /><Connector active /></>}
              <FlowNode step="Scope" icon={SCOPES[rule.scope.type].icon} tone="violet" title={SCOPES[rule.scope.type].label} value={scopeVal} active={sel === "scope"} onClick={() => setSel("scope")} />
              <Connector active />
              <FlowNode step="Action" icon={A.icon} tone={A.tone} title={A.label} value={actionVal} active={sel === "action"} onClick={() => setSel("action")} />
            </div>
          </div>

          <div className="summary-bar">
            <span className="summary-eyebrow"><Icons.zap size={13} /> Live summary</span>
            <SummaryLine rule={rule} />
            {error && <span className="tag amber" style={{ marginLeft: "auto" }}>{error}</span>}
          </div>
        </div>

        <aside className="inspector">
          <div className="insp-head">
            <span className="insp-step-ic">{(() => { const ic = sel === "trigger" ? T.icon : sel === "match" ? "filter" : sel === "scope" ? SCOPES[rule.scope.type].icon : A.icon; const I = Icons[ic]; return <I size={17} />; })()}</span>
            <div><div className="insp-title">{sel.charAt(0).toUpperCase() + sel.slice(1)}</div><div className="insp-sub">{ {trigger: "What starts this rule", match: "Which messages qualify", scope: "Where it applies", action: "What Wa does"}[sel] }</div></div>
          </div>

          <div className="insp-body">
            {sel === "trigger" && <>
              <label className="field-label">Trigger type</label>
              <RadioCards value={rule.trigger.type} onChange={setTriggerType} options={[
                { value: "message", label: "Incoming message", icon: "message" },
                { value: "group_join", label: "Member joins group", icon: "userPlus" },
                { value: "schedule", label: "Schedule", icon: "clock" },
              ]} />
              {rule.trigger.type === "schedule" && <ScheduleComposer schedule={{ ...DEFAULT_SCHEDULE, ...(rule.trigger.schedule || {}) }} cron={rule.trigger.cron} update={upSchedule} updateCron={(cron) => upT({ cron, schedule: { ...DEFAULT_SCHEDULE, ...(rule.trigger.schedule || {}), mode: "custom", cron } })} />}
            </>}

            {sel === "match" && <>
              <label className="field-label">Match mode</label>
              <RadioCards value={rule.match.mode} onChange={(v) => upM({ mode: v })} options={Object.entries(MATCH_MODES).map(([k, v]) => ({ value: k, label: v.label }))} />
              {rule.match.mode !== "any" && <div style={{ marginTop: 16 }}>
                <label className="field-label">Keyword</label>
                <input className="input" placeholder="e.g. price" value={rule.match.keyword} onChange={(e) => upM({ keyword: e.target.value })} />
                <button className="check-row" onClick={() => upM({ caseSensitive: !rule.match.caseSensitive })}>
                  <span className={"checkbox" + (rule.match.caseSensitive ? " on" : "")}>{rule.match.caseSensitive && <Icons.check size={12} />}</span>
                  Case sensitive
                </button>
              </div>}
            </>}

            {sel === "scope" && <>
              <label className="field-label">Where it runs</label>
              <RadioCards value={rule.scope.type} onChange={(v) => upS({ type: v })} options={[
                { value: "any", label: "Any chat", icon: "globe" },
                { value: "dm", label: "DMs only", icon: "message" },
                { value: "group", label: "A specific group", icon: "users" },
              ]} />
              {rule.scope.type === "group" && <div style={{ marginTop: 16 }}>
                <label className="field-label">Group</label>
                <select className="select" value={rule.scope.groupName || ""} onChange={(e) => upS({ groupName: e.target.value, groupId: groups.find(g => g.name === e.target.value)?.id })}>
                  <option value="" disabled>Select a group…</option>
                  {groups.map((g) => <option key={g.id} value={g.name}>{g.name} · {g.memberCount}</option>)}
                </select>
                {groupsError && <p className="insp-hint">{groupsError}. Connect WhatsApp to load live groups.</p>}
                <p className="insp-hint">Pulled live from <code className="mono">/api/groups</code>. Admin actions need the account to be a group admin.</p>
              </div>}
            </>}

            {sel === "action" && <>
              <label className="field-label">Do this</label>
              <RadioCards value={rule.action.type} onChange={(v) => upA({ type: v })} options={Object.entries(ACTIONS).map(([k, v]) => ({ value: k, label: v.label, icon: v.icon }))} />
              {(rule.action.type === "send_group") && <div style={{ marginTop: 16 }}>
                <label className="field-label">Target group</label>
                <select className="select" value={rule.action.targetGroupId || ""} onChange={(e) => upA({ targetGroupId: e.target.value })}>
                  <option value="" disabled>Select a group…</option>
                  {groups.map((g) => <option key={g.id} value={g.id}>{g.name}</option>)}
                </select>
                {groupsError && <p className="insp-hint">{groupsError}. Connect WhatsApp to load live groups.</p>}
              </div>}
              {A.needsMsg && <div style={{ marginTop: 16 }}>
                <label className="field-label">Message</label>
                <MessageComposer
                  value={rule.action.message}
                  onChange={(message) => upA({ message })}
                  placeholder="Type the message Wa will send..."
                  minHeight={150}
                  previewTitle="Action preview"
                />
                <p className="insp-hint">{rule.action.message.length} chars · sends are throttled 3–10s to protect the account.</p>
              </div>}
              {rule.action.type === "openai_reply" && <ChatGptActionFields action={rule.action} update={upA} onTest={test} testing={testing} />}
              {(testOutput || testError) && <div className={"test-output" + (testError ? " error" : "")} aria-live="polite">
                <div className="test-output-head">
                  <span><Icons.play size={13} /> Test output</span>
                  <button className="mini-link" onClick={() => { setTestOutput(""); setTestError(""); }}>Clear</button>
                </div>
                <pre>{testError || testOutput}</pre>
              </div>}
              {(rule.action.type === "remove_sender" || rule.action.type === "lock_group" || rule.action.type === "unlock_group") &&
                <div className="insp-callout"><Icons.shield size={15} /><span>Requires the linked account to be an <b>admin</b> of the target group.</span></div>}
            </>}
          </div>

          <div className="insp-foot">
            <button className="check-row" style={{ margin: 0 }} onClick={() => up({ enabled: !rule.enabled })}>
              <span className={"toggle" + (rule.enabled ? " on" : "")}></span>
              <span style={{ marginLeft: 4 }}>Enable on save</span>
            </button>
          </div>
        </aside>
      </div>
    </div>
  );
}

function ChatGptActionFields({ action, update, onTest, testing }) {
  const instructions = action.instructions || "";
  const repeatWindowDays = Number(action.repeatWindowDays ?? 7);
  const useQuoteTemplate = () => update({ instructions: QUOTE_PROMPT_TEMPLATE, repeatWindowDays: repeatWindowDays || 7 });

  return (
    <div className="ai-action-panel">
      <div className="ai-panel-head">
        <span className="ai-panel-ic"><Icons.message size={15} /></span>
        <div>
          <div className="ai-panel-title">ChatGPT output</div>
          <p>The Settings Markdown context is attached automatically.</p>
        </div>
      </div>

      <div className="ai-field-group">
        <div className="field-row">
          <label className="field-label">Instructions</label>
          <div className="field-actions">
            <button className="mini-link" onClick={useQuoteTemplate}>Quote format</button>
            {instructions && <button className="mini-link" onClick={() => update({ instructions: "" })}>Clear</button>}
          </div>
        </div>
        <textarea
          className="textarea ai-prompt"
          placeholder={'Example: Generate one quote in this format:\\nTopic line\\n\\n"Quote body"\\n\\n- Author'}
          value={instructions}
          onChange={(e) => update({ instructions: e.target.value })}
        ></textarea>
        <p className="insp-hint">Use this for format, tone, source rules, and limits for this automation.</p>
      </div>

      <div className="ai-grid">
        <div>
          <label className="field-label">Model override</label>
          <input className="input mono" placeholder="Use Settings default" value={action.model || ""} onChange={(e) => update({ model: e.target.value })} />
        </div>
        <div>
          <label className="field-label">Repeat memory</label>
          <div className="number-with-unit">
            <input
              className="input"
              type="number"
              min="1"
              max="90"
              value={repeatWindowDays}
              onChange={(e) => update({ repeatWindowDays: Number(e.target.value || 7) })}
            />
            <span>days</span>
          </div>
        </div>
      </div>

      <div className="ai-test-row">
        <button className="btn ghost sm" onClick={onTest} disabled={testing}><Icons.play size={14} /> {testing ? "Testing..." : "Run test"}</button>
        <span>Preview only. Nothing is sent to WhatsApp.</span>
      </div>
    </div>
  );
}

function validateRule(rule) {
  if (!rule.name.trim()) return "Name required";
  if (rule.trigger.type === "message" && rule.match.mode !== "any" && !rule.match.keyword.trim()) return "Keyword required";
  if (rule.scope.type === "group" && !rule.scope.groupId) return "Group required";
  if (rule.action.type === "send_group" && !rule.action.targetGroupId) return "Target group required";
  if ((rule.action.type === "reply" || rule.action.type === "send_group") && !rule.action.message.trim()) return "Message required";
  if (rule.trigger.type === "schedule") {
    if (!rule.trigger.cron?.trim()) return "Schedule required";
    if (["reply", "remove_sender"].includes(rule.action.type)) return "Schedule needs send group, Ask ChatGPT, lock group, or unlock group";
    if (rule.action.type === "openai_reply" && rule.scope.type !== "group") return "Pick a group scope for scheduled ChatGPT output";
    if (["lock_group", "unlock_group"].includes(rule.action.type) && rule.scope.type !== "group") return "Pick a group scope for scheduled group actions";
  }
  return "";
}

function ScheduleComposer({ schedule, cron, update, updateCron }) {
  const toggleWeekday = (value) => {
    const set = new Set(schedule.weekdays || []);
    if (set.has(value)) set.delete(value);
    else set.add(value);
    update({ weekdays: Array.from(set).sort() });
  };

  return (
    <div className="schedule-box">
      <label className="field-label">Recurrence</label>
      <div className="schedule-mode-grid">
        {[
          ["once", "Once"],
          ["daily", "Daily"],
          ["weekdays", "Weekdays"],
          ["weekly", "Weekly"],
          ["monthly", "Monthly"],
          ["hourly_window", "Hourly window"],
          ["custom", "Custom"],
        ].map(([value, label]) => (
          <button key={value} className={"schedule-chip" + (schedule.mode === value ? " on" : "")} onClick={() => update(value === "custom" ? { mode: value, cron } : { mode: value })}>{label}</button>
        ))}
      </div>

      {schedule.mode === "once" && <div className="schedule-grid">
        <div><label className="field-label">Date</label><input className="input" type="date" value={schedule.date} onChange={(e) => update({ date: e.target.value })} /></div>
        <div><label className="field-label">Time</label><input className="input" type="time" value={schedule.time} onChange={(e) => update({ time: e.target.value })} /></div>
      </div>}

      {schedule.mode === "hourly_window" && <div className="schedule-grid">
        <div><label className="field-label">From</label><input className="input" type="time" value={schedule.startTime} onChange={(e) => update({ startTime: e.target.value })} /></div>
        <div><label className="field-label">Until</label><input className="input" type="time" value={schedule.endTime} onChange={(e) => update({ endTime: e.target.value })} /></div>
      </div>}

      {["daily", "weekdays", "weekly", "monthly"].includes(schedule.mode) && <div className="schedule-grid">
        <div><label className="field-label">Time</label><input className="input" type="time" value={schedule.time} onChange={(e) => update({ time: e.target.value })} /></div>
        {schedule.mode === "weekly" && <div><label className="field-label">Day</label><select className="select" value={schedule.weekday} onChange={(e) => update({ weekday: e.target.value })}>{WEEKDAYS.map(([v, l]) => <option key={v} value={v}>{l}</option>)}</select></div>}
        {schedule.mode === "monthly" && <div><label className="field-label">Day of month</label><input className="input" type="number" min="1" max="31" value={schedule.dayOfMonth} onChange={(e) => update({ dayOfMonth: e.target.value })} /></div>}
      </div>}

      {schedule.mode === "weekdays" && <div className="weekday-row">
        {WEEKDAYS.slice(1, 6).map(([value, label]) => (
          <button key={value} className={"weekday-pill" + ((schedule.weekdays || []).includes(value) ? " on" : "")} onClick={() => toggleWeekday(value)}>{label}</button>
        ))}
      </div>}

      {schedule.mode === "custom" && <div style={{ marginTop: 14 }}>
        <label className="field-label">Cron expression</label>
        <input className="input mono" placeholder="0 22 * * *" value={cron || ""} onChange={(e) => updateCron(e.target.value)} />
      </div>}

      <div style={{ marginTop: 14 }}>
        <label className="field-label">Timezone</label>
        <select className="select" value={schedule.timezone} onChange={(e) => update({ timezone: e.target.value })}>
          <option value="Africa/Lagos">Africa/Lagos (WAT)</option>
          <option value="UTC">UTC</option>
          <option value="Europe/London">Europe/London</option>
          <option value="America/New_York">America/New_York</option>
        </select>
      </div>

      <div className="cron-preview">
        <span>Railway cron</span>
        <code className="mono">{cron || buildCron(schedule)}</code>
      </div>
      <p className="insp-hint">Railway runs the Node service continuously; the backend registers this cron with the selected timezone.</p>
    </div>
  );
}

function buildCron(schedule) {
  if (schedule.mode === "custom") return schedule.cron || "";
  const [hour = "9", minute = "0"] = String(schedule.time || "09:00").split(":");
  const h = Number(hour);
  const m = Number(minute);
  if (schedule.mode === "once") {
    const [, month = "*", day = "*"] = String(schedule.date || "").split("-");
    return `${m} ${h} ${Number(day)} ${Number(month)} *`;
  }
  if (schedule.mode === "daily") return `${m} ${h} * * *`;
  if (schedule.mode === "weekdays") return `${m} ${h} * * ${(schedule.weekdays || ["1", "2", "3", "4", "5"]).join(",")}`;
  if (schedule.mode === "weekly") return `${m} ${h} * * ${schedule.weekday || "1"}`;
  if (schedule.mode === "monthly") return `${m} ${h} ${schedule.dayOfMonth || 1} * *`;
  if (schedule.mode === "hourly_window") return `${Number(String(schedule.startTime || "06:00").split(":")[1] || 0)} ${hourWindow(String(schedule.startTime || "06:00").split(":")[0], String(schedule.endTime || "01:00").split(":")[0])} * * *`;
  return "";
}

function scheduleLabel(schedule = {}, cron = "") {
  const s = { ...DEFAULT_SCHEDULE, ...schedule };
  const time = s.time || "09:00";
  if (s.mode === "once") return `${s.date || "date"} at ${time}`;
  if (s.mode === "daily") return `Daily at ${time}`;
  if (s.mode === "weekdays") return `Weekdays at ${time}`;
  if (s.mode === "weekly") return `${WEEKDAYS.find(([v]) => v === s.weekday)?.[1] || "Weekly"} at ${time}`;
  if (s.mode === "monthly") return `Monthly on day ${s.dayOfMonth || 1} at ${time}`;
  if (s.mode === "hourly_window") return `Hourly ${s.startTime || "06:00"}-${s.endTime || "01:00"}`;
  return cron || "Custom cron";
}

function hourWindow(start, end) {
  const s = Number(start);
  const e = Number(end);
  if (Number.isNaN(s) || Number.isNaN(e)) return "*";
  if (s <= e) return `${s}-${e}`;
  return `${s}-23,0-${e}`;
}

window.BuilderScreen = BuilderScreen;
