// KueSync — Companion actions
// © 2026 Krometis Analytics. All rights reserved.
//
// Every navigation command fans out to ALL agent machines configured on this connection and uses
// ABSOLUTE slide targets, so the whole fleet stays locked to the same slide and self-corrects.

export function getActions(self) {
  const modeOption = {
    type: 'dropdown', id: 'mode', label: 'Mode', default: 'relative',
    choices: [
      { id: 'relative', label: 'Builds — plays in-slide builds/animations, synced by timing (default)' },
      { id: 'synced', label: 'Static — absolute slide, self-correcting, SKIPS in-slide builds' },
    ],
  }
  // Target only some machines (advance/jump a subset) or, blank/"all", the whole fleet.
  const machinesOption = {
    type: 'textinput', id: 'machines', useVariables: true, default: '',
    label: 'Machines — blank or "all" = whole fleet. Otherwise comma-separate machine numbers and/or IPs (you can mix), e.g. "1,3" or "192.168.1.51, 192.168.1.52" or "1, 192.168.1.55".',
  }
  return {
    // ---------------- basic navigation ----------------
    next: { name: 'Next', options: [modeOption, machinesOption], callback: async (a) => self.next(a.options.mode || 'relative', await self.parseVariablesInString(a.options.machines || '')) },
    prev: { name: 'Previous', options: [modeOption, machinesOption], callback: async (a) => self.prev(a.options.mode || 'relative', await self.parseVariablesInString(a.options.machines || '')) },

    goto: {
      name: 'Go to slide (number)',
      options: [
        { type: 'textinput', id: 'slide', label: 'Slide number', default: '1', useVariables: true },
        machinesOption,
      ],
      callback: async (a) => {
        const n = Number(await self.parseVariablesInString(a.options.slide))
        const machines = await self.parseVariablesInString(a.options.machines || '')
        if (Number.isFinite(n) && n > 0) self.gotoSlide(n, machines)
      },
    },

    jump: {
      name: 'Jump forward / back by N slides',
      options: [
        { type: 'dropdown', id: 'dir', label: 'Direction', default: 'forward', choices: [
          { id: 'forward', label: 'Forward' }, { id: 'back', label: 'Back' },
        ] },
        { type: 'number', id: 'count', label: 'Slides', default: 5, min: 1, max: 999 },
        machinesOption,
      ],
      callback: async (a) => self.jump(a.options.dir, Number(a.options.count) || 1, await self.parseVariablesInString(a.options.machines || '')),
    },

    // ---------------- launch a numbered show (0.10.0) ----------------
    // Open a numbered deck from KueSync Link on specific machines / groups, full screen at slide 1. The show
    // dropdown auto-populates from the fleet (a deck whose name starts with a number, e.g. "006 Welcome.pptx").
    launch_show: {
      name: 'Launch numbered show (KueSync Link)',
      options: [
        { type: 'dropdown', id: 'show', label: 'Show (numbered deck in KueSync Link)', default: '', choices: self.showChoices(), allowCustom: true,
          tooltip: 'Pick a numbered deck (or type its number). It opens on the chosen machines at slide 1, full screen.' },
        machinesOption,
      ],
      callback: async (a) => self.launchShow(await self.parseVariablesInString(a.options.show || ''), await self.parseVariablesInString(a.options.machines || '')),
    },

    // ---------------- media transport (PowerPoint; Windows) ----------------
    media_playpause: { name: 'Media: play / pause video (PowerPoint)', options: [machinesOption], callback: async (a) => self.media('media_playpause', await self.parseVariablesInString(a.options.machines || '')) },
    media_end:       { name: 'Media: jump to end of video (PowerPoint)', options: [machinesOption], callback: async (a) => self.media('media_end', await self.parseVariablesInString(a.options.machines || '')) },
    media_stop:      { name: 'Media: stop video (PowerPoint)', options: [machinesOption], callback: async (a) => self.media('media_stop', await self.parseVariablesInString(a.options.machines || '')) },
    open_file: {
      name: 'Open / load a presentation file',
      options: [ { type: 'textinput', id: 'path', label: 'File path (.key / .pptx)', default: '', useVariables: true },
        { type: 'textinput', id: 'password', label: 'Deck password (optional — Keynote 15.2+ opens protected decks)', default: '', useVariables: true },
        machinesOption ],
      callback: async (a) => self.openFile(await self.parseVariablesInString(a.options.path || ''), await self.parseVariablesInString(a.options.machines || ''), await self.parseVariablesInString(a.options.password || '')),
    },

    first: { name: 'First slide', options: [], callback: () => self.gotoSlide(1) },
    last: { name: 'Last slide', options: [], callback: () => self.last() },
    start: { name: 'Start slideshow (all machines)', options: [], callback: () => self.sendCommand({ action: 'start' }) },
    stop: { name: 'Stop / end slideshow (all machines)', options: [], callback: () => self.sendCommand({ action: 'stop' }) },

    // ---------------- sync helper ----------------
    sync_now: {
      name: 'Sync Now — match every machine to the Leader',
      options: [
        { type: 'static-text', id: 'info', label: 'What this does',
          value: 'One tap snaps the whole fleet to the Leader’s current slide (from Companion’s view the primary machine IS the Leader), realigning any Follower that drifted, reconnected, or was advanced on its own. It jumps straight to that slide and SKIPS any in-slide builds, so use it between builds — a great "panic re-align" button.' },
      ],
      callback: () => self.resync(0),
    },
    resync: {
      name: 'Resync all machines (snap to a specific slide)',
      options: [
        { type: 'textinput', id: 'slide', label: 'Slide (blank = current primary slide)', default: '', useVariables: true },
      ],
      callback: async (a) => {
        const raw = (await self.parseVariablesInString(a.options.slide || '')).trim()
        const n = raw ? Number(raw) : 0
        self.resync(Number.isFinite(n) ? n : 0)
      },
    },

    // ---------------- follower Active (0.9.6 / picker 0.9.8) ----------------
    // Park / un-park one follower. Pick it from the live dropdown (by DEVICE NAME · IP — matches the leader's
    // labeling) so a button always hits the right physical machine regardless of IP-box order. You can still
    // type a machine number (1–8) or an IP (allowCustom), so older buttons keep working. Pair with the
    // "Follower active" feedback for a green/red button that both controls and shows state.
    follower_activate: {
      name: 'Follower — Activate (rejoin the show)',
      options: [
        { type: 'dropdown', id: 'machine', label: 'Follower (by name · IP)', default: (self.followerChoices()[0] || {}).id || '1', choices: self.followerChoices(), allowCustom: true, tooltip: 'Pick the machine by its name. You can also type a machine number (1–8) or an IP.' },
        { type: 'checkbox', id: 'resync', label: 'Snap it to the fleet’s current slide when it rejoins', default: true },
      ],
      callback: async (a) => {
        const m = (await self.parseVariablesInString(String(a.options.machine || ''))).trim()
        self.setFollowerActive(m, true, { resync: a.options.resync !== false })
      },
    },
    follower_deactivate: {
      name: 'Follower — Deactivate (park / sit out)',
      options: [
        { type: 'dropdown', id: 'machine', label: 'Follower (by name · IP)', default: (self.followerChoices()[0] || {}).id || '1', choices: self.followerChoices(), allowCustom: true, tooltip: 'Pick the machine by its name. You can also type a machine number (1–8) or an IP.' },
      ],
      callback: async (a) => {
        const m = (await self.parseVariablesInString(String(a.options.machine || ''))).trim()
        self.setFollowerActive(m, false)
      },
    },
    follower_toggle_active: {
      name: 'Follower — Toggle Active / Inactive',
      options: [
        { type: 'dropdown', id: 'machine', label: 'Follower (by name · IP)', default: (self.followerChoices()[0] || {}).id || '1', choices: self.followerChoices(), allowCustom: true, tooltip: 'Pick the machine by its name. You can also type a machine number (1–8) or an IP.' },
        { type: 'checkbox', id: 'resync', label: 'When activating, snap it to the fleet’s current slide', default: true },
      ],
      callback: async (a) => {
        const m = (await self.parseVariablesInString(String(a.options.machine || ''))).trim()
        const next = !self.followerActiveOf(m)        // flip from the machine's current state
        self.setFollowerActive(m, next, { resync: a.options.resync !== false })
      },
    },

    // ---------------- deck control ----------------
    go_deck: {
      name: 'Go deck (full screen at slide 1, hold — no auto-advance)',
      options: [],
      callback: () => self.goDeck(),
    },
    end_show: {
      name: 'End show (stop the roll/cue AND exit the slideshow on all machines)',
      options: [],
      callback: () => self.endShow(),
    },
    flash_test: {
      name: 'Flash test (every machine\'s /flash page paints white at the same instant)',
      options: [],
      callback: () => self.sendCommand({ action: 'flash' }),
    },

    // ---------------- timed cue / loop ----------------
    run_cue: {
      name: 'Run cue (auto-advance with per-slide timing)',
      options: [
        { type: 'number', id: 'defaultDwell', label: 'Default slide timing (seconds)', default: 10, min: 1, max: 86400 },
        { type: 'textinput', id: 'perSlide', label: 'Override default timing per slide (e.g. 7=120, 12=30) — works with builds too', default: '' },
        { type: 'checkbox', id: 'fromStart', label: 'Start from slide 1', default: false },
        { type: 'checkbox', id: 'loop', label: 'Loop deck (restart at the end)', default: false },
        { type: 'checkbox', id: 'builds', label: 'Play in-slide builds & animations (synced steps; assumes identical decks) — DEFAULT', default: true },
      ],
      callback: (a) =>
        self.runCue({
          defaultDwell: a.options.defaultDwell,
          perSlide: a.options.perSlide,
          fromStart: !!a.options.fromStart,
          loop: !!a.options.loop,
          builds: !!a.options.builds,
        }),
    },
    pause_cue: { name: 'Cue: pause', options: [], callback: () => self.pauseCue() },
    resume_cue: { name: 'Cue: resume', options: [], callback: () => self.resumeCue() },
    cancel_cue: { name: 'Cue: cancel', options: [], callback: () => self.cancelCue() },

    // ---------------- KueSync Timer (show timer) ----------------
    // Set & run the fleet-wide show timer from a stream deck. Commands go to the Leader, which fans the
    // timer to every machine (clickers + every full-screen /clock). Pair with the "KueSync Timer status" feedback
    // and the $(kuetimer:kuetimer_time) variable for a live button.
    kuetimer_start: {
      name: 'KueSync Timer: Set & start (countdown)',
      options: [
        { type: 'number', id: 'minutes', label: 'Limit — minutes', default: 5, min: 0, max: 1440 },
        { type: 'number', id: 'seconds', label: 'Limit — plus seconds', default: 0, min: 0, max: 59 },
        { type: 'number', id: 'warn', label: 'Warn at (seconds remaining; 0 = none)', default: 60, min: 0, max: 86400 },
        { type: 'dropdown', id: 'end', label: 'At zero', default: 'blink', choices: [
          { id: 'blink', label: 'Blink 0:00' }, { id: 'zero', label: 'Hold 0:00' }, { id: 'up', label: 'Count overtime (red)' } ] },
      ],
      callback: (a) => {
        const dur = ((Number(a.options.minutes) || 0) * 60 + (Number(a.options.seconds) || 0)) * 1000
        self.timerCmd({ action: 'set', mode: 'down', durationMs: dur, warnMs: (Number(a.options.warn) || 0) * 1000, endAction: a.options.end || 'blink' })
        self.timerCmd({ action: 'start' })
      },
    },
    kuetimer_toggle: { name: 'KueSync Timer: Start / Pause (toggle)', options: [], callback: () => self.timerCmd({ action: 'toggle' }) },
    kuetimer_pause: { name: 'KueSync Timer: Pause', options: [], callback: () => self.timerCmd({ action: 'pause' }) },
    kuetimer_resume: { name: 'KueSync Timer: Resume', options: [], callback: () => self.timerCmd({ action: 'start' }) },
    kuetimer_reset: { name: 'KueSync Timer: Reset (back to the set limit)', options: [], callback: () => self.timerCmd({ action: 'reset' }) },
    kuetimer_zero: { name: 'KueSync Timer: Jump to zero', options: [], callback: () => self.timerCmd({ action: 'zero' }) },
    kuetimer_adjust: {
      name: 'KueSync Timer: Add / subtract time on the fly',
      options: [ { type: 'number', id: 'delta', label: 'Seconds (negative subtracts)', default: 60, min: -86400, max: 86400 } ],
      callback: (a) => self.timerCmd({ action: 'adjust', deltaMs: (Number(a.options.delta) || 0) * 1000 }),
    },
    kuetimer_countup: { name: 'KueSync Timer: Count up (from zero)', options: [], callback: () => { self.timerCmd({ action: 'set', mode: 'up' }); self.timerCmd({ action: 'start' }) } },
    kuetimer_tod: { name: 'KueSync Timer: Time of day', options: [], callback: () => { self.timerCmd({ action: 'set', mode: 'tod' }); self.timerCmd({ action: 'start' }) } },

    // ---------------- licensing ----------------
    revalidate: {
      name: 'Re-validate license',
      options: [],
      callback: () => { self.license.setKey(self.config.licenseKey); self.refreshLicenseUi() },
    },
  }
}
