#!/usr/bin/env node
/* eslint-disable @typescript-eslint/no-require-imports */

/**
 * Interactive setup script for private prompts.chat clones.
 * Configures branding, theme, authentication, and features.
 * 
 * Usage: node scripts/setup.js
 */

const fs = require('fs');
const path = require('path');
const crypto = require('crypto');
const { execSync, spawn } = require('child_process');
const p = require('@clack/prompts');
const color = require('picocolors');

const CONFIG_FILE = path.join(__dirname, '..', 'prompts.config.ts');
const ENV_FILE = path.join(__dirname, '..', '.env');

function generateAuthSecret() {
  return crypto.randomBytes(32).toString('base64');
}

function buildDatabaseUrl(config) {
  const { host, port, username, password, database } = config;
  return `postgresql://${username}:${password}@${host}:${port}/${database}`;
}

function generateEnvFile(config) {
  const isLocalhost = config.env.domain.includes('localhost');
  const protocol = isLocalhost ? 'http' : 'https';
  
  let envContent = `# Generated by setup script
# prompts.chat environment configuration

# Database
DATABASE_URL="${config.env.databaseUrl}"

# Authentication
AUTH_SECRET="${config.env.authSecret}"
AUTH_URL="${protocol}://${config.env.domain}"
AUTH_TRUST_HOST=true

# Cron Job Secret
CRON_SECRET="${crypto.randomBytes(16).toString('hex')}"
`;

  if (config.auth.providers.includes('github')) {
    envContent += `
# GitHub OAuth (configure at https://github.com/settings/developers)
AUTH_GITHUB_ID=""
AUTH_GITHUB_SECRET=""
`;
  }

  if (config.auth.providers.includes('google')) {
    envContent += `
# Google OAuth (configure at https://console.cloud.google.com/apis/credentials)
AUTH_GOOGLE_ID=""
AUTH_GOOGLE_SECRET=""
`;
  }

  if (config.auth.providers.includes('apple')) {
    envContent += `
# Apple Sign In
AUTH_APPLE_ID=""
AUTH_APPLE_SECRET=""
`;
  }

  if (config.auth.providers.includes('azure')) {
    envContent += `
# Microsoft Azure AD
AUTH_AZURE_AD_CLIENT_ID=""
AUTH_AZURE_AD_CLIENT_SECRET=""
AUTH_AZURE_AD_ISSUER=""
`;
  }

  if (config.features.aiSearch || config.features.aiGeneration) {
    envContent += `
# AI Features
OPENAI_API_KEY=""
# OPENAI_BASE_URL=https://api.openai.com/v1
# OPENAI_EMBEDDING_MODEL=text-embedding-3-small
# OPENAI_GENERATIVE_MODEL=gpt-4o-mini
`;
  }

  return envContent;
}

function generateConfig(config) {
  const sponsorsSection = config.sponsors.length > 0 
    ? `[
        ${config.sponsors.map(s => `{ name: "${s.name}", logo: "${s.logo}", url: "${s.url}" }`).join(',\n        ')}
      ]`
    : '[]';

  return `import { defineConfig } from "@/lib/config";

// Private clone configuration - generated by setup script
const useCloneBranding = true;

export default defineConfig({
  // Branding - your organization's identity
  branding: {
    name: "${config.branding.name}",
    logo: "${config.branding.logo}",
    logoDark: "${config.branding.logoDark}",
    favicon: "${config.branding.favicon}",
    description: "${config.branding.description}",
  },

  // Theme - design system configuration
  theme: {
    radius: "${config.theme.radius}",
    variant: "${config.theme.variant}",
    density: "${config.theme.density}",
    colors: {
      primary: "${config.theme.primaryColor}",
    },
  },

  // Authentication plugins
  auth: {
    providers: [${config.auth.providers.map(provider => `"${provider}"`).join(', ')}],
    allowRegistration: ${config.auth.allowRegistration},
  },

  // Internationalization
  i18n: {
    locales: [${config.i18n.locales.map(l => `"${l}"`).join(', ')}],
    defaultLocale: "${config.i18n.defaultLocale}",
  },

  // Features
  features: {
    privatePrompts: ${config.features.privatePrompts},
    changeRequests: ${config.features.changeRequests},
    categories: ${config.features.categories},
    tags: ${config.features.tags},
    comments: ${config.features.comments},
    aiSearch: ${config.features.aiSearch},
    aiGeneration: ${config.features.aiGeneration},
    mcp: ${config.features.mcp},
  },

  // Homepage customization (clone branding mode)
  homepage: {
    useCloneBranding,
    achievements: {
      enabled: false, // Disabled for private clones
    },
    sponsors: {
      enabled: ${config.sponsors.length > 0},
      items: ${sponsorsSection},
    },
  },
});
`;
}

function handleCancel() {
  p.cancel('Setup cancelled.');
  process.exit(0);
}

async function main() {
  console.clear();
  
  p.intro(color.bgCyan(color.black(' prompts.chat - Private Clone Setup ')));

  const config = {
    env: {},
    branding: {},
    theme: {},
    auth: {},
    i18n: {},
    features: {},
    sponsors: []
  };

  // === ENVIRONMENT ===
  p.log.step(color.cyan('Environment Configuration'));

  const envConfig = await p.group({
    domain: () => p.text({
      message: 'Application domain',
      placeholder: 'localhost:3000',
      defaultValue: 'localhost:3000',
    }),
  }, { onCancel: handleCancel });

  config.env.domain = envConfig.domain;
  config.env.authSecret = generateAuthSecret();

  // === DATABASE ===
  p.log.step(color.cyan('Database Configuration'));

  const dbConfig = await p.group({
    host: () => p.text({
      message: 'Database host',
      placeholder: 'localhost',
      defaultValue: 'localhost',
    }),
    port: () => p.text({
      message: 'Database port',
      placeholder: '5432',
      defaultValue: '5432',
    }),
    database: () => p.text({
      message: 'Database name',
      placeholder: 'prompts',
      defaultValue: 'prompts',
    }),
    username: () => p.text({
      message: 'Database username',
      placeholder: 'postgres',
      defaultValue: 'postgres',
    }),
    password: () => p.password({
      message: 'Database password',
      mask: '*',
    }),
  }, { onCancel: handleCancel });

  config.env.database = dbConfig;
  config.env.databaseUrl = buildDatabaseUrl(dbConfig);

  // === BRANDING ===
  p.log.step(color.cyan('Branding'));
  
  const branding = await p.group({
    name: () => p.text({
      message: 'Organization/App name',
      placeholder: 'My Prompt Library',
      defaultValue: 'My Prompt Library',
    }),
    description: () => p.text({
      message: 'Description',
      placeholder: 'Collect, organize, and share AI prompts',
      defaultValue: 'Collect, organize, and share AI prompts',
    }),
    logo: () => p.text({
      message: 'Logo path (public folder)',
      placeholder: '/logo.svg',
      defaultValue: '/logo.svg',
    }),
    logoDark: ({ results }) => p.text({
      message: 'Dark mode logo path',
      placeholder: results.logo || '/logo.svg',
      defaultValue: results.logo || '/logo.svg',
    }),
    favicon: () => p.text({
      message: 'Favicon path',
      placeholder: '/logo.svg',
      defaultValue: '/logo.svg',
    }),
  }, { onCancel: handleCancel });
  
  config.branding = branding;

  // === THEME ===
  p.log.step(color.cyan('Theme'));

  const theme = await p.group({
    primaryColor: () => p.text({
      message: 'Primary color (hex)',
      placeholder: '#6366f1',
      defaultValue: '#6366f1',
      validate: (value) => {
        if (!/^#[0-9A-Fa-f]{6}$/.test(value)) {
          return 'Please enter a valid hex color (e.g., #6366f1)';
        }
      },
    }),
    radius: () => p.select({
      message: 'Border radius style',
      initialValue: 'sm',
      options: [
        { value: 'none', label: 'None', hint: 'Sharp corners' },
        { value: 'sm', label: 'Small', hint: 'Subtle rounding' },
        { value: 'md', label: 'Medium', hint: 'Moderate rounding' },
        { value: 'lg', label: 'Large', hint: 'Very rounded' },
      ],
    }),
    variant: () => p.select({
      message: 'UI variant',
      initialValue: 'default',
      options: [
        { value: 'default', label: 'Default', hint: 'Standard modern look' },
        { value: 'flat', label: 'Flat', hint: 'Minimal shadows' },
        { value: 'brutal', label: 'Brutal', hint: 'Bold neo-brutalist style' },
      ],
    }),
    density: () => p.select({
      message: 'Spacing density',
      initialValue: 'default',
      options: [
        { value: 'compact', label: 'Compact', hint: 'Tighter spacing' },
        { value: 'default', label: 'Default', hint: 'Balanced spacing' },
        { value: 'comfortable', label: 'Comfortable', hint: 'More breathing room' },
      ],
    }),
  }, { onCancel: handleCancel });
  
  config.theme = theme;

  // === AUTHENTICATION ===
  p.log.step(color.cyan('Authentication'));

  const authProviders = await p.multiselect({
    message: 'Select authentication providers',
    options: [
      { value: 'credentials', label: 'Email/Password', hint: 'Traditional auth (recommended)' },
      { value: 'github', label: 'GitHub OAuth', hint: 'Most popular for developers' },
      { value: 'google', label: 'Google OAuth', hint: 'Widely used' },
      { value: 'apple', label: 'Apple Sign In', hint: 'Sign in with Apple' },
      { value: 'azure', label: 'Microsoft Azure AD', hint: 'Enterprise SSO' },
    ],
    initialValues: ['credentials'],
    required: false,
  });

  if (p.isCancel(authProviders)) handleCancel();

  config.auth.providers = authProviders.length > 0 ? authProviders : ['credentials'];
  
  if (config.auth.providers.length === 0) {
    p.log.warn('No providers selected, defaulting to credentials');
    config.auth.providers = ['credentials'];
  }

  if (config.auth.providers.includes('credentials')) {
    const allowReg = await p.confirm({
      message: 'Allow public registration?',
      initialValue: true,
    });
    if (p.isCancel(allowReg)) handleCancel();
    config.auth.allowRegistration = allowReg;
  } else {
    config.auth.allowRegistration = false;
  }

  // === INTERNATIONALIZATION ===
  p.log.step(color.cyan('Internationalization'));

  const selectedLocales = await p.multiselect({
    message: 'Select supported languages',
    options: [
      { value: 'en', label: 'English', hint: 'Default' },
      { value: 'es', label: 'Spanish' },
      { value: 'fr', label: 'French' },
      { value: 'de', label: 'German' },
      { value: 'it', label: 'Italian' },
      { value: 'pt', label: 'Portuguese' },
      { value: 'tr', label: 'Turkish' },
      { value: 'az', label: 'Azerbaijani' },
      { value: 'ja', label: 'Japanese' },
      { value: 'ko', label: 'Korean' },
      { value: 'zh', label: 'Chinese' },
      { value: 'ru', label: 'Russian' },
      { value: 'ar', label: 'Arabic', hint: 'RTL' },
      { value: 'fa', label: 'Persian', hint: 'RTL' },
      { value: 'he', label: 'Hebrew', hint: 'RTL' },
      { value: 'el', label: 'Greek' },
    ],
    required: false,
  });

  if (p.isCancel(selectedLocales)) handleCancel();

  config.i18n.locales = selectedLocales.length > 0 ? selectedLocales : ['en'];
  
  if (config.i18n.locales.length > 1) {
    const defaultLocale = await p.select({
      message: 'Default locale',
      options: config.i18n.locales.map(l => ({ value: l, label: l })),
    });
    if (p.isCancel(defaultLocale)) handleCancel();
    config.i18n.defaultLocale = defaultLocale;
  } else {
    config.i18n.defaultLocale = config.i18n.locales[0];
  }

  // === FEATURES ===
  p.log.step(color.cyan('Features'));

  const features = await p.multiselect({
    message: 'Enable features',
    options: [
      { value: 'privatePrompts', label: 'Private Prompts', hint: 'Users can create private prompts' },
      { value: 'changeRequests', label: 'Change Requests', hint: 'Version control system' },
      { value: 'categories', label: 'Categories', hint: 'Organize prompts by category' },
      { value: 'tags', label: 'Tags', hint: 'Tag-based organization' },
      { value: 'comments', label: 'Comments', hint: 'Allow comments on prompts' },
      { value: 'aiSearch', label: 'AI Search', hint: 'Requires OPENAI_API_KEY' },
      { value: 'aiGeneration', label: 'AI Generation', hint: 'AI-powered prompt generation (requires OPENAI_API_KEY)' },
      { value: 'mcp', label: 'MCP Support', hint: 'Model Context Protocol features & API keys' },
    ],
    initialValues: ['privatePrompts', 'changeRequests', 'categories', 'tags', 'comments'],
    required: false,
  });

  if (p.isCancel(features)) handleCancel();

  config.features = {
    privatePrompts: features.includes('privatePrompts'),
    changeRequests: features.includes('changeRequests'),
    categories: features.includes('categories'),
    tags: features.includes('tags'),
    comments: features.includes('comments'),
    aiSearch: features.includes('aiSearch'),
    aiGeneration: features.includes('aiGeneration'),
    mcp: features.includes('mcp'),
  };

  // === SPONSORS ===
  p.log.step(color.cyan('Sponsors (Optional)'));

  const addSponsors = await p.confirm({
    message: 'Add sponsor logos to homepage?',
    initialValue: false,
  });

  if (p.isCancel(addSponsors)) handleCancel();
  
  if (addSponsors) {
    let addMore = true;
    while (addMore) {
      const sponsor = await p.group({
        name: () => p.text({ message: 'Sponsor name', placeholder: 'Acme Inc' }),
        logo: () => p.text({ message: 'Logo URL', placeholder: '/sponsors/acme.svg' }),
        url: () => p.text({ message: 'Website URL', placeholder: 'https://acme.com' }),
      }, { onCancel: handleCancel });
      
      if (sponsor.name && sponsor.logo && sponsor.url) {
        config.sponsors.push(sponsor);
        p.log.success(`Added ${sponsor.name}`);
      }
      
      const another = await p.confirm({
        message: 'Add another sponsor?',
        initialValue: false,
      });
      if (p.isCancel(another)) handleCancel();
      addMore = another;
    }
  }

  // === SUMMARY ===
  p.log.step(color.cyan('Configuration Summary'));
  
  const summaryLines = [
    `${color.dim('Name:')}           ${config.branding.name}`,
    `${color.dim('Description:')}    ${config.branding.description}`,
    `${color.dim('Primary Color:')}  ${config.theme.primaryColor}`,
    `${color.dim('UI Style:')}       ${config.theme.variant} / ${config.theme.radius} radius`,
    `${color.dim('Auth:')}           ${config.auth.providers.join(', ')}`,
    `${color.dim('Languages:')}      ${config.i18n.locales.join(', ')}`,
    `${color.dim('Features:')}       ${Object.entries(config.features).filter(([,v]) => v).map(([k]) => k).join(', ')}`,
  ];
  
  if (config.sponsors.length > 0) {
    summaryLines.push(`${color.dim('Sponsors:')}       ${config.sponsors.map(s => s.name).join(', ')}`);
  }
  
  p.note(summaryLines.join('\n'), 'Review your configuration');

  const proceed = await p.confirm({
    message: 'Generate configuration file?',
    initialValue: true,
  });

  if (p.isCancel(proceed) || !proceed) {
    p.cancel('Setup cancelled.');
    process.exit(0);
  }

  // === GENERATE CONFIG ===
  const s = p.spinner();
  s.start('Generating configuration...');
  
  // Backup existing config if it exists
  if (fs.existsSync(CONFIG_FILE)) {
    const backupPath = CONFIG_FILE + '.backup';
    fs.copyFileSync(CONFIG_FILE, backupPath);
  }

  const configContent = generateConfig(config);
  fs.writeFileSync(CONFIG_FILE, configContent);
  
  s.stop('Generated prompts.config.ts');

  // === ENV FILE ===
  s.start('Creating .env file...');
  
  const envContent = generateEnvFile(config);
  fs.writeFileSync(ENV_FILE, envContent);
  
  s.stop('Created .env file');

  // === DATABASE SETUP ===
  const setupDb = await p.confirm({
    message: 'Create database and run migrations now?',
    initialValue: true,
  });

  if (!p.isCancel(setupDb) && setupDb) {
    // Create database
    s.start(`Creating database "${config.env.database.database}"...`);
    try {
      const createDbCmd = `createdb -h ${config.env.database.host} -p ${config.env.database.port} -U ${config.env.database.username} ${config.env.database.database}`;
      execSync(createDbCmd, { 
        stdio: 'pipe',
        env: { ...process.env, PGPASSWORD: config.env.database.password }
      });
      s.stop(`Created database "${config.env.database.database}"`);
    } catch (err) {
      if (err.message.includes('already exists')) {
        s.stop(`Database "${config.env.database.database}" already exists`);
      } else {
        s.stop(color.yellow(`Could not create database (may already exist or createdb not available)`));
        p.log.warn(`You may need to create the database manually: createdb ${config.env.database.database}`);
      }
    }

    // Run db:setup (generate + migrate + seed)
    s.start('Running database setup (prisma generate + migrate)...');
    try {
      execSync('npm run db:setup', { 
        stdio: 'inherit',
        cwd: path.join(__dirname, '..'),
        env: { ...process.env, DATABASE_URL: config.env.databaseUrl }
      });
      s.stop('Database setup complete');
    } catch (err) {
      s.stop(color.red('Database setup failed'));
      p.log.error('Run manually: npm run db:setup');
    }
  }

  // === ADDITIONAL ENV VARS NEEDED ===
  const additionalEnvVars = [];
  
  if (config.auth.providers.includes('github')) {
    additionalEnvVars.push('AUTH_GITHUB_ID     - GitHub OAuth client ID');
    additionalEnvVars.push('AUTH_GITHUB_SECRET - GitHub OAuth client secret');
  }
  if (config.auth.providers.includes('google')) {
    additionalEnvVars.push('AUTH_GOOGLE_ID     - Google OAuth client ID');
    additionalEnvVars.push('AUTH_GOOGLE_SECRET - Google OAuth client secret');
  }
  if (config.auth.providers.includes('azure')) {
    additionalEnvVars.push('AUTH_AZURE_AD_CLIENT_ID     - Azure AD client ID');
    additionalEnvVars.push('AUTH_AZURE_AD_CLIENT_SECRET - Azure AD client secret');
    additionalEnvVars.push('AUTH_AZURE_AD_ISSUER        - Azure AD issuer URL');
  }
  if (config.auth.providers.includes('apple')) {
    additionalEnvVars.push('AUTH_APPLE_ID              - Apple Services ID');
    additionalEnvVars.push('AUTH_APPLE_SECRET          - Apple secret key');
  }
  if (config.features.aiSearch || config.features.aiGeneration) {
    additionalEnvVars.push('OPENAI_API_KEY     - OpenAI API key for AI features');
  }

  if (additionalEnvVars.length > 0) {
    p.log.warn(color.yellow('⚠️  Action required: You must configure the following in .env before the app will work:'));
    additionalEnvVars.forEach(v => p.log.message(`   ${color.yellow('→')} ${v}`));
    p.log.message('');
  }

  // === NEXT STEPS ===
  const nextSteps = additionalEnvVars.length > 0
    ? `1. Edit ${color.cyan('.env')} to add OAuth credentials (if using OAuth providers)\n` +
      `2. Add your logo files to the ${color.cyan('public/')} folder\n` +
      `3. Run: ${color.cyan('npm run db:push')}\n` +
      `4. Run: ${color.cyan('npm run db:seed')} (optional - seed with prompts)\n` +
      `5. Run: ${color.cyan('npm run dev')}`
    : `1. Add your logo files to the ${color.cyan('public/')} folder\n` +
      `2. Run: ${color.cyan('npm run db:push')}\n` +
      `3. Run: ${color.cyan('npm run db:seed')} (optional - seed with prompts)\n` +
      `4. Run: ${color.cyan('npm run dev')}`;
  
  p.note(nextSteps, 'Next steps');

  p.outro(color.green('Setup complete! See SELF-HOSTING.md for more details.'));
}

main().catch((err) => {
  p.log.error('Setup failed: ' + err.message);
  process.exit(1);
});
