#!/usr/bin/env node
// Idempotent server-side fixtures for the List Organizer E2E flow
// (e2e/flows/lists-organize.yaml). The organizer renders the active Mastodon
// account's follows (left column) and lists (right rail); a clean bot has
// neither, so the screen would show only empty states and the flow could assert
// nothing real. This ensures the mastodon slot has:
//
//   - a list titled "Halflight E2E" (so a colour token renders) — created once;
//   - at least one follow (so a follow row renders) — the first *local*
//     directory account the bot isn't already following, followed once.
//
// The list is left empty on purpose: the row starts with no membership dots, so
// a drop (when a human or a future gesture-capable runner performs it) is what
// turns one green. Idempotent — re-running is a no-op once both exist.
// Best-effort: any failure is a host-free warning, never a hard exit; the flow
// degrades to whatever rendered. Mastodon-only (Pixelfed's /api/v1/lists is a
// stub); the pixelfed slot is skipped. Slot-keyed output only — no hostname or
// handle reaches the terminal scrollback.

import { readFileSync } from 'node:fs'
import { dirname, resolve } from 'node:path'
import { fileURLToPath } from 'node:url'

const __dirname = dirname(fileURLToPath(import.meta.url))
const LIST_TITLE = 'Halflight E2E'

/** Same resolution order as the other dev scripts: arg → env → repo default. */
function resolveRigPath() {
  const fromArg = process.argv[2]
  if (fromArg && fromArg.length > 0) return fromArg
  const env = process.env.HALFLIGHT_TEST_RIG
  if (env && env.length > 0) return env
  return resolve(__dirname, '..', '..', 'secrets', 'test-rigs', 'halflight.test.json')
}

async function ensureSlot(slot, entry) {
  const base = `https://${entry.instance}`
  const headers = {
    Authorization: `Bearer ${entry.accessToken}`,
    Accept: 'application/json',
  }
  const get = (path) => fetch(`${base}${path}`, { headers })
  const post = (path, params) =>
    fetch(`${base}${path}`, {
      method: 'POST',
      headers: { ...headers, 'Content-Type': 'application/x-www-form-urlencoded' },
      body: new URLSearchParams(params).toString(),
    })

  // 1. A list named LIST_TITLE so the right rail has a drop-target token.
  let lists = []
  try {
    const r = await get('/api/v1/lists')
    if (r.ok) lists = await r.json()
  } catch (e) {
    console.warn(`[fixtures] ${slot}: list fetch error — ${e.message}`)
  }
  if (Array.isArray(lists) && lists.some((l) => l?.title === LIST_TITLE)) {
    console.log(`[fixtures] ${slot}: list "${LIST_TITLE}" already present.`)
  } else {
    const r = await post('/api/v1/lists', { title: LIST_TITLE })
    console.log(`[fixtures] ${slot}: create list "${LIST_TITLE}" → HTTP ${r.status}`)
  }

  // 2. At least one follow so the left column has a row.
  let following = []
  try {
    const r = await get(`/api/v1/accounts/${entry.userId}/following?limit=1`)
    if (r.ok) following = await r.json()
  } catch (e) {
    console.warn(`[fixtures] ${slot}: following fetch error — ${e.message}`)
  }
  if (Array.isArray(following) && following.length > 0) {
    console.log(`[fixtures] ${slot}: already following ≥1 account.`)
    return
  }

  // Discover a local account to follow (local so the follow lands synchronously
  // rather than federating asynchronously).
  let dir = []
  try {
    const r = await get('/api/v1/directory?local=true&limit=8&order=active')
    if (r.ok) dir = await r.json()
  } catch (e) {
    console.warn(`[fixtures] ${slot}: directory fetch error — ${e.message}`)
  }
  const target = (Array.isArray(dir) ? dir : []).find(
    (a) => String(a?.id) !== String(entry.userId)
  )
  if (!target) {
    console.warn(
      `[fixtures] ${slot}: no local directory account to follow — left column stays empty.`
    )
    return
  }
  const r = await post(`/api/v1/accounts/${target.id}/follow`, {})
  console.log(`[fixtures] ${slot}: follow a local account → HTTP ${r.status}`)
}

async function main() {
  let parsed
  try {
    parsed = JSON.parse(readFileSync(resolveRigPath(), 'utf8'))
  } catch {
    console.log('[fixtures] no usable rig file — nothing to seed.')
    return
  }
  const rigs = parsed.rigs ?? {}
  const targets = Object.entries(rigs).filter(([, e]) => e && e.type === 'mastodon')
  if (targets.length === 0) {
    console.log('[fixtures] no mastodon slot — nothing to seed.')
    return
  }
  for (const [slot, entry] of targets) await ensureSlot(slot, entry)
}

await main()
