import { sdk } from '../sdk'

/**
 * verify-database — StartOS Package Action.
 *
 * Operator confidence check. Runs SQLite's `PRAGMA integrity_check` and
 * a `PRAGMA quick_check` against /data/app.db, plus a few row-count
 * sanity queries. Reports the results in the StartOS UI as a
 * structured `result` so the operator can spot anomalies at a glance
 * without dropping into a shell.
 *
 * Use cases:
 *   - "Did the StartOS Backup last night actually capture a healthy
 *     DB?" (Run the action AFTER a backup completes; integrity_check
 *     ok means the file is consistent.)
 *   - "I had a power loss / the host crashed — is the DB ok?"
 *   - "I just sideloaded a fresh image — did the seed copy correctly?"
 *
 * Read-only. Safe to run while the service is running. We use
 * allowedStatuses: 'only-running' so the SQL goes through the live
 * service's data-mounted subcontainer rather than starting one.
 */

export const verifyDatabase = sdk.Action.withoutInput(
  'verify-database',
  async () => ({
    name: 'Verify database integrity',
    description:
      "Read-only. Runs SQLite PRAGMA integrity_check + quick_check against /data/app.db and reports row counts. Useful after a backup, a host crash, or a fresh sideload.",
    warning: null,
    visibility: 'enabled',
    allowedStatuses: 'only-running',
    group: null,
  }),
  async ({ effects }) => {
    let result = { integrity: 'unknown', quickCheck: 'unknown', counts: {} as Record<string, string> }

    await sdk.SubContainer.withTemp(
      effects,
      { imageId: 'main' },
      sdk.Mounts.of().mountVolume({
        volumeId: 'main',
        subpath: null,
        mountpoint: '/data',
        readonly: true,
      }),
      'verify-database',
      async (sc) => {
        const sql = [
          "SELECT 'integrity:' || (SELECT * FROM pragma_integrity_check LIMIT 1);",
          "SELECT 'quick:' || (SELECT * FROM pragma_quick_check LIMIT 1);",
          "SELECT 'count:' || 'User' || '=' || (SELECT COUNT(*) FROM User);",
          "SELECT 'count:' || 'Workout' || '=' || (SELECT COUNT(*) FROM Workout WHERE deletedAt IS NULL);",
          "SELECT 'count:' || 'Exercise' || '=' || (SELECT COUNT(*) FROM Exercise);",
          "SELECT 'count:' || 'SetLog' || '=' || (SELECT COUNT(*) FROM SetLog);",
          "SELECT 'count:' || 'Session' || '=' || (SELECT COUNT(*) FROM Session WHERE expiresAt > CURRENT_TIMESTAMP);",
        ].join('\n')

        const res = await sc.execFail(['sqlite3', '/data/app.db'], { input: sql }, 60_000)
        const lines = res.stdout
          .toString()
          .split('\n')
          .map((s) => s.trim())
          .filter(Boolean)

        for (const line of lines) {
          if (line.startsWith('integrity:')) {
            result.integrity = line.slice('integrity:'.length)
          } else if (line.startsWith('quick:')) {
            result.quickCheck = line.slice('quick:'.length)
          } else if (line.startsWith('count:')) {
            const [name, value] = line.slice('count:'.length).split('=')
            if (name && value !== undefined) {
              result.counts[name] = value
            }
          }
        }
      },
    )

    const ok = result.integrity === 'ok' && result.quickCheck === 'ok'

    return {
      version: '1',
      title: ok ? 'Database is healthy' : 'Database integrity issues detected',
      message: ok
        ? 'integrity_check + quick_check both returned ok. Row counts below.'
        : `integrity_check returned: ${result.integrity}; quick_check returned: ${result.quickCheck}. Investigate before relying on the next backup.`,
      result: {
        type: 'group',
        value: [
          {
            type: 'single',
            name: 'integrity_check',
            description: 'PRAGMA integrity_check result. Should be "ok".',
            value: result.integrity,
            copyable: false,
            qr: false,
            masked: false,
          },
          {
            type: 'single',
            name: 'quick_check',
            description: 'PRAGMA quick_check result. Should be "ok".',
            value: result.quickCheck,
            copyable: false,
            qr: false,
            masked: false,
          },
          ...Object.entries(result.counts).map(([name, value]) => ({
            type: 'single' as const,
            name: `${name} rows`,
            description: name === 'Session' ? 'Active (unexpired) sessions.' : null,
            value,
            copyable: false,
            qr: false,
            masked: false,
          })),
        ],
      },
    }
  },
)
