#!/usr/bin/env bun
/**
 * Scaffolds Supabase integration files in a Humand sandbox project.
 * Called by the /setup-supabase skill after Claude has created the Supabase
 * project via MCP and has the credentials in hand.
 *
 * Usage:
 *   bun scaffold.ts \
 *     --project-dir <path> \
 *     --project-id <supabase-project-id> \
 *     --project-ref <ref> \
 *     --project-url <https://xxx.supabase.co> \
 *     --service-role-key <key>
 *
 * Writes:
 *   - .env.local         (real values, never committed)
 *   - .env.example       (committed, non-secret placeholders + docs)
 *   - supabase/migrations/ (empty folder, ready for migrations)
 * Installs:
 *   - @supabase/supabase-js (runtime for the serverless proxy)
 *
 * Does NOT touch .gitignore — that's the /security-checkup skill's job
 * (applied globally across all integrations, not per-service).
 *
 * The /connect-service skill creates the actual api/supabase/[...path].ts
 * proxy — this script only prepares the ground.
 */

import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
import { join } from 'node:path';
import { spawnSync } from 'node:child_process';

type Args = {
  projectDir: string;
  projectId: string;
  projectRef: string;
  projectUrl: string;
  serviceRoleKey: string;
};

function parseArgs(argv: string[]): Args {
  const flags: Record<string, string> = {};
  for (let i = 0; i < argv.length; i += 2) {
    const k = argv[i];
    const v = argv[i + 1];
    if (!k?.startsWith('--') || v === undefined) {
      throw new Error(`Bad argument near: ${k}`);
    }
    flags[k.slice(2)] = v;
  }
  const required = ['project-dir', 'project-id', 'project-ref', 'project-url', 'service-role-key'];
  for (const r of required) {
    if (!flags[r]) throw new Error(`Missing required arg: --${r}`);
  }
  return {
    projectDir: flags['project-dir']!,
    projectId: flags['project-id']!,
    projectRef: flags['project-ref']!,
    projectUrl: flags['project-url']!,
    serviceRoleKey: flags['service-role-key']!,
  };
}

const log = (msg: string) => process.stderr.write(`▶ ${msg}\n`);
const ok = (msg: string) => process.stderr.write(`✓ ${msg}\n`);

function upsertEnv(filePath: string, entries: Record<string, string>): void {
  const existing = existsSync(filePath) ? readFileSync(filePath, 'utf8') : '';
  const lines = existing.split('\n');
  const keys = new Set(Object.keys(entries));
  const out: string[] = [];
  const seen = new Set<string>();

  for (const line of lines) {
    const match = line.match(/^([A-Z0-9_]+)=/);
    if (match && keys.has(match[1])) {
      out.push(`${match[1]}=${entries[match[1]]}`);
      seen.add(match[1]);
    } else {
      out.push(line);
    }
  }
  for (const [k, v] of Object.entries(entries)) {
    if (!seen.has(k)) {
      if (out.length && out[out.length - 1] !== '') out.push('');
      out.push(`${k}=${v}`);
    }
  }
  writeFileSync(filePath, out.join('\n'));
}

function appendEnvExampleSection(filePath: string, ref: string, id: string, url: string): void {
  const existing = existsSync(filePath) ? readFileSync(filePath, 'utf8') : '';
  if (existing.includes('# Supabase integration')) {
    ok('.env.example already has Supabase section — leaving as is');
    return;
  }
  const section = [
    '',
    '# Supabase integration',
    '# project_id, project_ref, and url are NOT secret — they appear in the dashboard URL.',
    '# service_role_key IS secret — only lives in the serverless proxy, never in the frontend.',
    `# Dashboard: https://supabase.com/dashboard/project/${ref}`,
    `SUPABASE_PROJECT_ID=${id}`,
    `SUPABASE_PROJECT_REF=${ref}`,
    `SUPABASE_URL=${url}`,
    'SUPABASE_SERVICE_ROLE_KEY=',
    '',
  ].join('\n');
  writeFileSync(filePath, existing + section);
  ok('.env.example updated');
}

function installSupabaseJs(projectDir: string): void {
  const pkgPath = join(projectDir, 'package.json');
  if (!existsSync(pkgPath)) {
    throw new Error(`package.json not found in ${projectDir}`);
  }
  const pkg = readFileSync(pkgPath, 'utf8');
  if (pkg.includes('"@supabase/supabase-js"')) {
    ok('@supabase/supabase-js already installed');
    return;
  }
  log('Installing @supabase/supabase-js');
  const result = spawnSync('bun', ['add', '@supabase/supabase-js'], {
    cwd: projectDir,
    stdio: 'inherit',
  });
  if (result.status !== 0) {
    throw new Error(`bun add @supabase/supabase-js failed (exit ${result.status})`);
  }
  ok('@supabase/supabase-js installed');
}

function main(): void {
  const args = parseArgs(process.argv.slice(2));
  const { projectDir, projectId, projectRef, projectUrl, serviceRoleKey } = args;

  if (!existsSync(projectDir)) {
    throw new Error(`project-dir does not exist: ${projectDir}`);
  }

  log('Writing .env.local');
  upsertEnv(join(projectDir, '.env.local'), {
    SUPABASE_PROJECT_ID: projectId,
    SUPABASE_PROJECT_REF: projectRef,
    SUPABASE_URL: projectUrl,
    SUPABASE_SERVICE_ROLE_KEY: serviceRoleKey,
  });
  ok('.env.local updated');

  log('Writing .env.example');
  appendEnvExampleSection(join(projectDir, '.env.example'), projectRef, projectId, projectUrl);

  log('Preparing supabase/migrations folder');
  const migrationsDir = join(projectDir, 'supabase', 'migrations');
  mkdirSync(migrationsDir, { recursive: true });
  const gitkeep = join(migrationsDir, '.gitkeep');
  if (!existsSync(gitkeep)) writeFileSync(gitkeep, '');
  ok('supabase/migrations ready');

  installSupabaseJs(projectDir);

  const summary = {
    projectDir,
    projectId,
    projectRef,
    projectUrl,
    dashboardUrl: `https://supabase.com/dashboard/project/${projectRef}`,
    files: {
      envLocal: '.env.local',
      envExample: '.env.example',
      migrationsDir: 'supabase/migrations',
    },
  };
  process.stdout.write(JSON.stringify(summary, null, 2) + '\n');
}

try {
  main();
} catch (err) {
  process.stderr.write(`✗ ${(err as Error).message}\n`);
  process.exit(1);
}
