import { sdk } from '../sdk'

/**
 * toggle-signups — StartOS Package Action.
 *
 * Sets `InstanceSettings.signupsOpen` (the multi-user signup gate).
 * When `true`, anyone with the URL can create an account from the app's
 * /auth/signup page. New users start with no admin privileges and the
 * full curated exercise library.
 *
 * The same toggle is also available in-app at Settings -> Instance
 * Settings (admin only). Both write to the same singleton row, so
 * either path works. This StartOS action is the safety hatch for
 * operators who don't have a working admin login (or aren't logged in
 * yet on first install).
 *
 * Design notes:
 *   - allowedStatuses: 'only-running'. The app must be running for the
 *     write to be visible without restart, and the subcontainer needs
 *     /data mounted writable. We don't require a stop because the
 *     UPDATE is a single-row write that can't conflict with the
 *     long-running Next.js server.
 *   - Single explicit boolean input. Avoids the "I clicked it but did it
 *     turn on or off?" ambiguity of toggle-style actions.
 *   - The action does NOT report the current state in `getInput`. It's a
 *     setter, not a viewer; the in-app Settings page is the dashboard.
 */

export const toggleSignups = sdk.Action.withInput(
  'toggle-signups',
  async () => ({
    name: 'Set new signups',
    description:
      'Allow or disallow anyone with the URL to create a Proof of Work account on this instance. The same toggle exists at in-app Settings -> Instance Settings (admin only).',
    warning:
      'When sign-ups are open, anyone who can reach the URL can create an account. Make sure the instance is on a network you trust (LAN, Tor, VPN) before enabling.',
    visibility: 'enabled',
    allowedStatuses: 'only-running',
    group: null,
  }),
  sdk.InputSpec.of({
    signupsOpen: sdk.Value.toggle({
      name: 'Allow new signups',
      description: 'On = anyone with the URL can register. Off = closed.',
      default: false,
    }),
  }),
  async () => null,
  async ({ effects, input }) => {
    const flag = input.signupsOpen ? 1 : 0

    await sdk.SubContainer.withTemp(
      effects,
      { imageId: 'main' },
      sdk.Mounts.of().mountVolume({
        volumeId: 'main',
        subpath: null,
        mountpoint: '/data',
        readonly: false,
      }),
      'toggle-signups',
      async (sc) => {
        // Defensive: make sure the table exists. The boot-time compat ALTERs
        // create it, but if this action runs before a first proper boot we
        // want it to still succeed.
        const sql = [
          `CREATE TABLE IF NOT EXISTS InstanceSettings (`,
          `  id INTEGER PRIMARY KEY DEFAULT 1,`,
          `  signupsOpen INTEGER NOT NULL DEFAULT 0,`,
          `  updatedAt DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP`,
          `);`,
          `INSERT OR IGNORE INTO InstanceSettings (id, signupsOpen) VALUES (1, ${flag});`,
          `UPDATE InstanceSettings SET signupsOpen = ${flag}, updatedAt = CURRENT_TIMESTAMP WHERE id = 1;`,
          `SELECT signupsOpen FROM InstanceSettings WHERE id = 1;`,
        ].join('\n')

        const res = await sc.execFail(
          ['sqlite3', '/data/app.db'],
          { input: sql },
          30_000,
        )
        const observed = res.stdout
          .toString()
          .split('\n')
          .map((s) => s.trim())
          .filter(Boolean)
          .pop()
        if (observed !== String(flag)) {
          throw new Error(
            `Aborting: wrote signupsOpen=${flag} but read back ${observed}. /data/app.db may be corrupt.`,
          )
        }
      },
    )

    return {
      version: '1',
      title: input.signupsOpen ? 'Sign-ups enabled' : 'Sign-ups disabled',
      message: input.signupsOpen
        ? 'New visitors can now create accounts at /auth/signup.'
        : 'New sign-ups are now closed. Existing users can still sign in.',
      result: {
        type: 'group',
        value: [
          {
            type: 'single',
            name: 'signupsOpen',
            description: 'Current value of InstanceSettings.signupsOpen',
            value: String(input.signupsOpen),
            copyable: false,
            qr: false,
            masked: false,
          },
        ],
      },
    }
  },
)
