#!/usr/bin/env node
/**
 * Wordly.art - Setup Wizard (Node.js)
 *
 * Usage: node scripts/setup.js
 *
 * Ce script :
 * 1. Pose des questions interactives
 * 2. Genere les secrets
 * 3. Hash le mot de passe admin en bcrypt
 * 4. Ecrit le fichier .env
 * 5. Lance docker compose
 */

const readline = require('readline');
const crypto = require('crypto');
const fs = require('fs');
const path = require('path');
const { execSync } = require('child_process');

const ENV_FILE = path.join(__dirname, '..', '.env');

// ============================================
// Helpers
// ============================================

function rl() {
  return readline.createInterface({ input: process.stdin, output: process.stdout });
}

function question(prompt, defaultVal) {
  return new Promise(resolve => {
    const r = rl();
    const display = defaultVal ? `${prompt} [${defaultVal}]: ` : `${prompt}: `;
    r.question(display, answer => {
      r.close();
      resolve(answer.trim() || (defaultVal || ''));
    });
  });
}

function questionPassword(prompt) {
  return new Promise(resolve => {
    const r = rl();
    r.question(`${prompt}: `, answer => {
      r.close();
      resolve(answer);
    });
    // Hide input
    if (process.stdin.isTTY) {
      process.stdout.write('\x1b[8m'); // Hide
    }
  }).finally(() => {
    if (process.stdout.isTTY) {
      process.stdout.write('\x1b[0m'); // Show
    }
  });
}

function questionPasswordSimple(prompt) {
  return new Promise(resolve => {
    const r = readline.createInterface({ input: process.stdin, output: process.stdout });
    r.question(`${prompt}: `, answer => {
      r.close();
      resolve(answer);
    });
  });
}

function generateSecret(len = 64) {
  return crypto.randomBytes(len).toString('base64url').slice(0, len);
}

function generateHex(len = 32) {
  return crypto.randomBytes(len).toString('hex');
}

function hashBcrypt(password) {
  try {
    const safePass = password.replace(/'/g, "'\"'\"'");
    const cmd = 'docker run --rm python:3.12-slim bash -c "' +
      "pip install 'passlib[bcrypt]' bcrypt >/dev/null 2>&1 && " +
      "python3 -c \\\"from passlib.context import CryptContext; " +
      "print(CryptContext(schemes=['bcrypt']).hash('" + safePass + "'))\\\"" +
      '"';
    const result = execSync(cmd, { encoding: 'utf-8', timeout: 120000, stdio: ['pipe', 'pipe', 'pipe'] });
    return result.trim();
  } catch (e) {
    return null;
  }
}

function writeEnv(content) {
  fs.writeFileSync(ENV_FILE, content, 'utf-8');
  // On Linux: chmod 600
  try { fs.chmodSync(ENV_FILE, 0o600); } catch (e) { /* Windows */ }
}

function readEnv() {
  if (!fs.existsSync(ENV_FILE)) return {};
  const content = fs.readFileSync(ENV_FILE, 'utf-8');
  const env = {};
  for (const line of content.split('\n')) {
    const trimmed = line.trim();
    if (!trimmed || trimmed.startsWith('#')) continue;
    const eqIdx = trimmed.indexOf('=');
    if (eqIdx === -1) continue;
    const key = trimmed.slice(0, eqIdx);
    const val = trimmed.slice(eqIdx + 1);
    env[key] = val;
  }
  return env;
}

function setEnvValues(pairs) {
  let content = '';
  if (fs.existsSync(ENV_FILE)) {
    content = fs.readFileSync(ENV_FILE, 'utf-8');
  }
  for (const [key, value] of Object.entries(pairs)) {
    const regex = new RegExp(`^${key}=.*$`, 'm');
    if (regex.test(content)) {
      content = content.replace(regex, `${key}=${value}`);
    } else {
      content += `\n${key}=${value}`;
    }
  }
  writeEnv(content);
}

async function select(prompt, options) {
  console.log(`\n${prompt}`);
  options.forEach((opt, i) => console.log(`  ${i + 1}) ${opt.label}`));
  const answer = await question('Choix', '1');
  const idx = parseInt(answer) - 1;
  return options[Math.max(0, Math.min(idx, options.length - 1))].value;
}

// ============================================
// Main
// ============================================

async function main() {
  const C = {
    RED: '\x1b[0;31m', GREEN: '\x1b[0;32m', YELLOW: '\x1b[1;33m',
    CYAN: '\x1b[0;36m', BOLD: '\x1b[1m', NC: '\x1b[0m',
  };

  console.log(`\n${C.CYAN}${C.BOLD}=========================================${C.NC}`);
  console.log(`${C.CYAN}${C.BOLD}  Wordly.art - Setup Wizard${C.NC}`);
  console.log(`${C.CYAN}${C.BOLD}=========================================${C.NC}\n`);

  // Check we're in the right directory
  if (!fs.existsSync(path.join(__dirname, '..', 'docker-compose.yml'))) {
    console.log(`${C.RED}Erreur: lance ce script depuis la racine du projet${C.NC}`);
    console.log(`Usage: node scripts/setup.js`);
    process.exit(1);
  }

  // Read existing .env if present
  const existing = readEnv();

  // ===== 1. Domaine =====
  console.log(`\n${C.BOLD}--- Domaine ---${C.NC}`);
  const domain = await question('Nom de domaine', existing.DOMAIN || 'wordly.art');

  // ===== 2. Admin =====
  console.log(`\n${C.BOLD}--- Admin ---${C.NC}`);
  const adminUser = await question('Nom d\'utilisateur admin', existing.ADMIN_USERNAME || 'admin');
  const adminPass = await questionPasswordSimple('Mot de passe admin');
  if (!adminPass) {
    console.log(`${C.RED}Mot de passe obligatoire!${C.NC}`);
    process.exit(1);
  }
  const adminPass2 = await questionPasswordSimple('Confirmer');
  if (adminPass !== adminPass2) {
    console.log(`${C.RED}Ne correspondent pas!${C.NC}`);
    process.exit(1);
  }
  console.log(`${C.GREEN}OK${C.NC}`);

  // Hash bcrypt
  console.log(`${C.CYAN}Hashage bcrypt...${C.NC}`);
  const adminHash = hashBcrypt(adminPass);

  // ===== 3. Secrets auto =====
  console.log(`\n${C.BOLD}--- Secrets (auto) ---${C.NC}`);
  const jwtSecret = generateSecret(64);
  const adminTokenSecret = generateHex(32);
  const pgPassword = generateSecret(32);
  const grafanaPassword = generateSecret(24);
  console.log(`${C.GREEN}JWT, Admin Token, DB, Grafana generes${C.NC}`);

  // ===== 4. Provider =====
  console.log(`\n${C.BOLD}--- Service de traduction ---${C.NC}`);
  const providers = [
    { value: 'google', label: 'Google (gratuit, aucune cle)' },
    { value: 'deepseek', label: 'DeepSeek (~0.14$/M tokens, tres bon)' },
    { value: 'minimax', label: 'Minimax (MiniMax-M1 / m2.7)' },
    { value: 'ollama', label: 'Ollama (local, gratuit)' },
    { value: 'deepl', label: 'DeepL (haute qualite, 500k car/mois gratuit)' },
    { value: 'openai', label: 'OpenAI (GPT)' },
    { value: 'openrouter', label: 'OpenRouter (multi-modeles)' },
  ];
  const translationService = await select('Provider par defaut :', providers);

  // Provider config
  const prov = {
    GOOGLE_TRANSLATE_ENABLED: 'true',
    OLLAMA_ENABLED: 'false', OLLAMA_BASE_URL: 'http://ollama:11434', OLLAMA_MODEL: 'llama3',
    DEEPSEEK_ENABLED: 'false', DEEPSEEK_API_KEY: '', DEEPSEEK_MODEL: 'deepseek-chat', DEEPSEEK_BASE_URL: 'https://api.deepseek.com/v1',
    MINIMAX_ENABLED: 'false', MINIMAX_API_KEY: '', MINIMAX_MODEL: 'MiniMax-M1', MINIMAX_BASE_URL: 'https://api.minimax.chat/v1',
    DEEPL_ENABLED: 'false', DEEPL_API_KEY: '',
    OPENAI_ENABLED: 'false', OPENAI_API_KEY: '', OPENAI_MODEL: 'gpt-4o-mini', OPENAI_BASE_URL: 'https://api.openai.com/v1',
    OPENROUTER_ENABLED: 'false', OPENROUTER_API_KEY: '', OPENROUTER_MODEL: 'deepseek/deepseek-chat',
  };

  if (translationService === 'deepseek') {
    prov.DEEPSEEK_ENABLED = 'true';
    prov.DEEPSEEK_API_KEY = await question('Cle API DeepSeek (sk-...)', '');
    prov.DEEPSEEK_MODEL = await question('Modele', 'deepseek-chat');
  } else if (translationService === 'minimax') {
    prov.MINIMAX_ENABLED = 'true';
    prov.MINIMAX_API_KEY = await question('Cle API Minimax', '');
    prov.MINIMAX_MODEL = await question('Modele', 'MiniMax-M1');
  } else if (translationService === 'ollama') {
    prov.OLLAMA_ENABLED = 'true';
    prov.OLLAMA_BASE_URL = await question('URL Ollama', 'http://ollama:11434');
    prov.OLLAMA_MODEL = await question('Modele', 'llama3');
  } else if (translationService === 'deepl') {
    prov.DEEPL_ENABLED = 'true';
    prov.DEEPL_API_KEY = await question('Cle API DeepL', '');
  } else if (translationService === 'openai') {
    prov.OPENAI_ENABLED = 'true';
    prov.OPENAI_API_KEY = await question('Cle API OpenAI (sk-...)', '');
    prov.OPENAI_MODEL = await question('Modele', 'gpt-4o-mini');
  } else if (translationService === 'openrouter') {
    prov.OPENROUTER_ENABLED = 'true';
    prov.OPENROUTER_API_KEY = await question('Cle API OpenRouter (sk-or-...)', '');
    prov.OPENROUTER_MODEL = await question('Modele', 'deepseek/deepseek-chat');
  }

  // ===== 5. Stripe (optional) =====
  console.log(`\n${C.BOLD}--- Stripe (optionnel) ---${C.NC}`);
  const doStripe = await question('Configurer Stripe maintenant ? (oui/non)', 'non');
  const stripe = { SECRET_KEY: '', WEBHOOK_SECRET: '', STARTER_PRICE_ID: '', PRO_PRICE_ID: '', BUSINESS_PRICE_ID: '' };
  if (doStripe === 'oui') {
    stripe.SECRET_KEY = await question('Secret Key (sk_test_... ou sk_live_...)', '');
    stripe.WEBHOOK_SECRET = await question('Webhook Secret (whsec_...)', '');
    stripe.STARTER_PRICE_ID = await question('Price ID Starter (price_...)', '');
    stripe.PRO_PRICE_ID = await question('Price ID Pro (price_...)', '');
    stripe.BUSINESS_PRICE_ID = await question('Price ID Business (price_...)', '');
  }

  // ===== Resume =====
  console.log(`\n${C.CYAN}${C.BOLD}=========================================${C.NC}`);
  console.log(`${C.CYAN}${C.BOLD}  RESUME${C.NC}`);
  console.log(`${C.CYAN}${C.BOLD}=========================================${C.NC}`);
  console.log(`  Domaine:      ${domain}`);
  console.log(`  Admin:        ${adminUser} / ${adminPass}`);
  console.log(`  Traduction:   ${translationService}`);
  console.log(`  Bcrypt hash:  ${adminHash ? adminHash.substring(0, 20) + '...' : 'NON GENERE (mot de passe en clair)'}`);
  console.log(`  Stripe:       ${stripe.SECRET_KEY ? 'Configure' : 'Non configure'}`);
  console.log(``);

  const confirm = await question('Ecrire le .env ? (oui/non)', 'oui');
  if (confirm !== 'oui') { console.log('Annule.'); process.exit(0); }

  // ===== Write .env =====
  const lines = [
    `# Genere le ${new Date().toISOString().split('T')[0]} par setup.js`,
    ``,
    `# ---- App ----`,
    `APP_NAME=Wordly`,
    `APP_ENV=production`,
    `DEBUG=false`,
    `LOG_LEVEL=INFO`,
    ``,
    `# ---- Domaine ----`,
    `DOMAIN=${domain}`,
    `NEXT_PUBLIC_API_URL=https://${domain}`,
    `BACKEND_PORT=8000`,
    `FRONTEND_PORT=3000`,
    ``,
    `# ---- Traduction ----`,
    `TRANSLATION_SERVICE=${translationService}`,
    ``,
    `GOOGLE_TRANSLATE_ENABLED=${prov.GOOGLE_TRANSLATE_ENABLED}`,
    ``,
    `OLLAMA_ENABLED=${prov.OLLAMA_ENABLED}`,
    `OLLAMA_BASE_URL=${prov.OLLAMA_BASE_URL}`,
    `OLLAMA_MODEL=${prov.OLLAMA_MODEL}`,
    ``,
    `DEEPSEEK_ENABLED=${prov.DEEPSEEK_ENABLED}`,
    `DEEPSEEK_API_KEY=${prov.DEEPSEEK_API_KEY}`,
    `DEEPSEEK_MODEL=${prov.DEEPSEEK_MODEL}`,
    `DEEPSEEK_BASE_URL=${prov.DEEPSEEK_BASE_URL}`,
    ``,
    `MINIMAX_ENABLED=${prov.MINIMAX_ENABLED}`,
    `MINIMAX_API_KEY=${prov.MINIMAX_API_KEY}`,
    `MINIMAX_MODEL=${prov.MINIMAX_MODEL}`,
    `MINIMAX_BASE_URL=${prov.MINIMAX_BASE_URL}`,
    ``,
    `DEEPL_ENABLED=${prov.DEEPL_ENABLED}`,
    `DEEPL_API_KEY=${prov.DEEPL_API_KEY}`,
    ``,
    `OPENAI_ENABLED=${prov.OPENAI_ENABLED}`,
    `OPENAI_API_KEY=${prov.OPENAI_API_KEY}`,
    `OPENAI_MODEL=${prov.OPENAI_MODEL}`,
    `OPENAI_BASE_URL=${prov.OPENAI_BASE_URL}`,
    ``,
    `OPENROUTER_ENABLED=${prov.OPENROUTER_ENABLED}`,
    `OPENROUTER_API_KEY=${prov.OPENROUTER_API_KEY}`,
    `OPENROUTER_MODEL=${prov.OPENROUTER_MODEL}`,
    ``,
    `# ---- Upload ----`,
    `MAX_FILE_SIZE_MB=50`,
    `ALLOWED_EXTENSIONS=.docx,.xlsx,.pptx`,
    ``,
    `# ---- Rate Limiting ----`,
    `RATE_LIMIT_ENABLED=true`,
    `RATE_LIMIT_REQUESTS_PER_MINUTE=60`,
    `RATE_LIMIT_TRANSLATIONS_PER_MINUTE=10`,
    `RATE_LIMIT_TRANSLATIONS_PER_HOUR=100`,
    `RATE_LIMIT_TRANSLATIONS_PER_DAY=500`,
    ``,
    `# ---- Admin ----`,
    `ADMIN_USERNAME=${adminUser}`,
    `ADMIN_PASSWORD=${adminPass}`,
    adminHash ? `ADMIN_PASSWORD_HASH=${adminHash}` : `# ADMIN_PASSWORD_HASH= (mot de passe en clair dans ADMIN_PASSWORD)`,
    `JWT_SECRET_KEY=${jwtSecret}`,
    `ADMIN_TOKEN_SECRET=${adminTokenSecret}`,
    `CORS_ORIGINS=https://${domain}`,
    ``,
    `# ---- Database ----`,
    `POSTGRES_USER=translate`,
    `POSTGRES_PASSWORD=${pgPassword}`,
    `POSTGRES_DB=translate_db`,
    ``,
    `# ---- Monitoring ----`,
    `GRAFANA_USER=admin`,
    `GRAFANA_PASSWORD=${grafanaPassword}`,
    ``,
    `# ---- Stripe ----`,
    `STRIPE_SECRET_KEY=${stripe.SECRET_KEY}`,
    `STRIPE_WEBHOOK_SECRET=${stripe.WEBHOOK_SECRET}`,
    `STRIPE_STARTER_PRICE_ID=${stripe.STARTER_PRICE_ID}`,
    `STRIPE_PRO_PRICE_ID=${stripe.PRO_PRICE_ID}`,
    `STRIPE_BUSINESS_PRICE_ID=${stripe.BUSINESS_PRICE_ID}`,
    ``,
  ];

  writeEnv(lines.join('\n'));
  console.log(`${C.GREEN}.env ecrit!${C.NC}`);

  // ===== Offer to start =====
  console.log(`\n${C.BOLD}Prochaines etapes :${C.NC}`);
  console.log(`  1. Verifier:  cat .env`);
  console.log(`  2. Lancer:    docker compose up -d --build`);
  console.log(`  3. Tester:    curl http://localhost:8000/health`);
  console.log(``);

  const doStart = await question('Lancer docker compose maintenant ? (oui/non)', 'non');
  if (doStart === 'oui') {
    console.log(`${C.CYAN}Build et lancement...${C.NC}`);
    try {
      execSync('docker compose up -d --build', { stdio: 'inherit', cwd: path.join(__dirname, '..'), timeout: 600000 });
      console.log(`${C.GREEN}Demarre!${C.NC}`);
      console.log(`\nVerification...`);
      try {
        const health = execSync('curl -sf http://localhost:8000/health', { encoding: 'utf-8', timeout: 10000 });
        console.log(`  Health: ${health}`);
      } catch {
        console.log(`  ${C.YELLOW}Health check pas encore pret, attends 30s puis: curl http://localhost:8000/health${C.NC}`);
      }
      execSync('docker compose ps', { stdio: 'inherit', cwd: path.join(__dirname, '..') });
    } catch (e) {
      console.log(`${C.RED}Erreur docker. Verifie les logs: docker compose logs${C.NC}`);
    }
  }

  console.log(`\n${C.GREEN}${C.BOLD}Setup termine!${C.NC}`);
  console.log(`Admin: ${adminUser} / ${adminPass}`);
  console.log(`Grafana: admin / ${grafanaPassword}`);
}

main().catch(e => {
  console.error(`\nErreur: ${e.message}`);
  process.exit(1);
});
