#!/usr/bin/env node

/**
 * CLI pour créer un ou plusieurs établissements N3WT.
 *
 * Usage interactif :
 *   node scripts/create-establishment.js
 *
 * Usage batch (fichier JSON) :
 *   node scripts/create-establishment.js --file batch.json
 *
 * Format du fichier batch :
 * {
 *   "backendUrl": "http://localhost:8080",   // optionnel (fallback : URL_DJANGO dans conf/backend.env)
 *   "apiKey": "TOk3n1234!!",                 // optionnel (fallback : WEBHOOK_API_KEY dans conf/backend.env)
 *   "establishments": [
 *     {
 *       "name": "École Dupont",
 *       "address": "1 rue de la Paix, Paris",
 *       "total_capacity": 300,
 *       "establishment_type": [1, 2],        // 1=Maternelle, 2=Primaire, 3=Secondaire
 *       "evaluation_frequency": 1,           // 1=Trimestre, 2=Semestre, 3=Année
 *       "licence_code": "LIC001",            // optionnel
 *       "directeur": {
 *         "email": "directeur@dupont.fr",
 *         "password": "motdepasse123",
 *         "last_name": "Dupont",
 *         "first_name": "Jean"
 *       }
 *     }
 *   ]
 * }
 */

const readline = require("readline");
const http = require("http");
const https = require("https");
const fs = require("fs");
const path = require("path");

// ── Lecture de conf/backend.env ───────────────────────────────────────────────

function loadBackendEnv() {
  const envPath = path.join(__dirname, "..", "conf", "backend.env");
  if (!fs.existsSync(envPath)) return;

  const lines = fs.readFileSync(envPath, "utf8").split("\n");
  for (const line of lines) {
    const trimmed = line.trim();
    if (!trimmed || trimmed.startsWith("#")) continue;
    const eqIdx = trimmed.indexOf("=");
    if (eqIdx === -1) continue;
    const key = trimmed.slice(0, eqIdx).trim();
    let value = trimmed.slice(eqIdx + 1).trim();
    if (
      (value.startsWith('"') && value.endsWith('"')) ||
      (value.startsWith("'") && value.endsWith("'"))
    ) {
      value = value.slice(1, -1);
    }
    // Ne pas écraser les variables déjà définies dans l'environnement
    if (!(key in process.env)) {
      process.env[key] = value;
    }
  }
}

// ── Helpers readline ──────────────────────────────────────────────────────────

let rl;

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

function ask(question, defaultValue) {
  const suffix =
    defaultValue != null && defaultValue !== "" ? ` (${defaultValue})` : "";
  return new Promise((resolve) => {
    getRL().question(`${question}${suffix}: `, (answer) => {
      resolve(
        answer.trim() || (defaultValue != null ? String(defaultValue) : ""),
      );
    });
  });
}

function askRequired(question) {
  return new Promise((resolve) => {
    const prompt = () => {
      getRL().question(`${question}: `, (answer) => {
        if (!answer.trim()) {
          console.log("  ⚠  Ce champ est obligatoire.");
          prompt();
        } else {
          resolve(answer.trim());
        }
      });
    };
    prompt();
  });
}

function askChoices(question, choices) {
  return new Promise((resolve) => {
    console.log(`\n${question}`);
    choices.forEach((c, i) => console.log(`  ${i + 1}. ${c.label}`));
    const prompt = () => {
      getRL().question(
        "Choix (numéros séparés par des virgules): ",
        (answer) => {
          const nums = answer
            .split(",")
            .map((s) => parseInt(s.trim(), 10))
            .filter((n) => n >= 1 && n <= choices.length);
          if (nums.length === 0) {
            console.log("  ⚠  Sélectionnez au moins une option.");
            prompt();
          } else {
            resolve(nums.map((n) => choices[n - 1].value));
          }
        },
      );
    };
    prompt();
  });
}

function askChoice(question, choices, defaultIndex) {
  return new Promise((resolve) => {
    console.log(`\n${question}`);
    choices.forEach((c, i) =>
      console.log(
        `  ${i + 1}. ${c.label}${i === defaultIndex ? " (défaut)" : ""}`,
      ),
    );
    const prompt = () => {
      getRL().question(`Choix (1-${choices.length}): `, (answer) => {
        if (!answer.trim() && defaultIndex != null) {
          resolve(choices[defaultIndex].value);
          return;
        }
        const n = parseInt(answer.trim(), 10);
        if (n >= 1 && n <= choices.length) {
          resolve(choices[n - 1].value);
        } else {
          console.log("  ⚠  Choix invalide.");
          prompt();
        }
      });
    };
    prompt();
  });
}

// ── HTTP ──────────────────────────────────────────────────────────────────────

function postJSON(url, data, apiKey) {
  return new Promise((resolve, reject) => {
    const parsed = new URL(url);
    const mod = parsed.protocol === "https:" ? https : http;
    const body = JSON.stringify(data);

    const req = mod.request(
      {
        hostname: parsed.hostname,
        port: parsed.port,
        path: parsed.pathname,
        method: "POST",
        headers: {
          "Content-Type": "application/json",
          "Content-Length": Buffer.byteLength(body),
          "X-API-Key": apiKey,
        },
      },
      (res) => {
        let raw = "";
        res.on("data", (chunk) => (raw += chunk));
        res.on("end", () => {
          try {
            resolve({ status: res.statusCode, data: JSON.parse(raw) });
          } catch {
            resolve({ status: res.statusCode, data: raw });
          }
        });
      },
    );

    req.on("error", reject);
    req.write(body);
    req.end();
  });
}

// ── Création d'un établissement ───────────────────────────────────────────────

async function createEstablishment(backendUrl, apiKey, payload) {
  const url = `${backendUrl.replace(/\/$/, "")}/Establishment/establishments`;
  const res = await postJSON(url, payload, apiKey);
  return res;
}

// ── Validation basique d'un enregistrement batch ──────────────────────────────

function validateRecord(record, index) {
  const errors = [];
  const label = record.name ? `"${record.name}"` : `#${index + 1}`;

  if (!record.name) errors.push("name manquant");
  if (!record.address) errors.push("address manquant");
  if (!record.total_capacity) errors.push("total_capacity manquant");
  if (
    !Array.isArray(record.establishment_type) ||
    record.establishment_type.length === 0
  )
    errors.push("establishment_type manquant ou vide");
  if (!record.directeur) errors.push("directeur manquant");
  else {
    if (!record.directeur.email) errors.push("directeur.email manquant");
    if (!record.directeur.password) errors.push("directeur.password manquant");
    if (!record.directeur.last_name)
      errors.push("directeur.last_name manquant");
    if (!record.directeur.first_name)
      errors.push("directeur.first_name manquant");
  }

  if (errors.length > 0) {
    throw new Error(`Établissement ${label} invalide : ${errors.join(", ")}`);
  }
}

// ── Mode batch ────────────────────────────────────────────────────────────────

async function runBatch(filePath) {
  const absPath = path.resolve(filePath);
  if (!fs.existsSync(absPath)) {
    console.error(`❌ Fichier introuvable : ${absPath}`);
    process.exit(1);
  }

  let batch;
  try {
    batch = JSON.parse(fs.readFileSync(absPath, "utf8"));
  } catch (err) {
    console.error(`❌ Fichier JSON invalide : ${err.message}`);
    process.exit(1);
  }

  const backendUrl =
    batch.backendUrl || process.env.URL_DJANGO || "http://localhost:8080";
  const apiKey = batch.apiKey || process.env.WEBHOOK_API_KEY;

  if (!apiKey) {
    console.error(
      "❌ apiKey manquant dans le fichier batch ou la variable WEBHOOK_API_KEY.",
    );
    process.exit(1);
  }

  const establishments = batch.establishments;
  if (!Array.isArray(establishments) || establishments.length === 0) {
    console.error("❌ Le fichier batch ne contient aucun établissement.");
    process.exit(1);
  }

  // Validation préalable de tous les enregistrements
  establishments.forEach((record, i) => validateRecord(record, i));

  console.log(
    `\n📋 Batch : ${establishments.length} établissement(s) à créer sur ${backendUrl}\n`,
  );

  let success = 0;
  let failure = 0;

  for (let i = 0; i < establishments.length; i++) {
    const record = establishments[i];
    const label = `[${i + 1}/${establishments.length}] ${record.name}`;
    process.stdout.write(`  ${label} ... `);

    try {
      const res = await createEstablishment(backendUrl, apiKey, record);
      if (res.status === 201) {
        console.log(`✅ (ID: ${res.data.id})`);
        success++;
      } else {
        console.log(`❌ HTTP ${res.status}`);
        console.error(`    ${JSON.stringify(res.data)}`);
        failure++;
      }
    } catch (err) {
      console.log(`❌ Erreur réseau : ${err.message}`);
      failure++;
    }
  }

  console.log(`\nRésultat : ${success} créé(s), ${failure} échec(s).`);
  if (failure > 0) process.exit(1);
}

// ── Mode interactif ───────────────────────────────────────────────────────────

async function runInteractive() {
  console.log("╔══════════════════════════════════════════╗");
  console.log("║   Création d'un établissement N3WT       ║");
  console.log("╚══════════════════════════════════════════╝\n");

  const backendUrl = await ask(
    "URL du backend Django",
    process.env.URL_DJANGO || "http://localhost:8080",
  );
  const apiKey = await ask(
    "Clé API webhook (WEBHOOK_API_KEY)",
    process.env.WEBHOOK_API_KEY || "",
  );
  if (!apiKey) {
    console.error("❌ La clé API est obligatoire.");
    getRL().close();
    process.exit(1);
  }

  // --- Établissement ---
  console.log("\n── Établissement ──");
  const name = await askRequired("Nom de l'établissement");
  const address = await askRequired("Adresse");
  const totalCapacity = parseInt(await askRequired("Capacité totale"), 10);

  const establishmentType = await askChoices("Type(s) de structure:", [
    { label: "Maternelle", value: 1 },
    { label: "Primaire", value: 2 },
    { label: "Secondaire", value: 3 },
  ]);

  const evaluationFrequency = await askChoice(
    "Fréquence d'évaluation:",
    [
      { label: "Trimestre", value: 1 },
      { label: "Semestre", value: 2 },
      { label: "Année", value: 3 },
    ],
    0,
  );

  const licenceCode = await ask("Code licence (optionnel)", "");

  // --- Directeur (admin) ---
  console.log("\n── Compte directeur (admin) ──");
  const directorEmail = await askRequired("Email du directeur");
  const directorPassword = await askRequired("Mot de passe");
  const directorLastName = await askRequired("Nom de famille");
  const directorFirstName = await askRequired("Prénom");

  // --- Récapitulatif ---
  console.log("\n── Récapitulatif ──");
  console.log(`  Établissement : ${name}`);
  console.log(`  Adresse       : ${address}`);
  console.log(`  Capacité      : ${totalCapacity}`);
  console.log(`  Type(s)       : ${establishmentType.join(", ")}`);
  console.log(`  Évaluation    : ${evaluationFrequency}`);
  console.log(
    `  Directeur     : ${directorFirstName} ${directorLastName} <${directorEmail}>`,
  );

  const confirm = await ask("\nConfirmer la création ? (o/n)", "o");
  if (confirm.toLowerCase() !== "o") {
    console.log("Annulé.");
    getRL().close();
    process.exit(0);
  }

  const payload = {
    name,
    address,
    total_capacity: totalCapacity,
    establishment_type: establishmentType,
    evaluation_frequency: evaluationFrequency,
    ...(licenceCode && { licence_code: licenceCode }),
    directeur: {
      email: directorEmail,
      password: directorPassword,
      last_name: directorLastName,
      first_name: directorFirstName,
    },
  };

  console.log("\nCréation en cours...");
  try {
    const res = await createEstablishment(backendUrl, apiKey, payload);
    if (res.status === 201) {
      console.log("\n✅ Établissement créé avec succès !");
      console.log(`   ID : ${res.data.id}`);
      console.log(`   Nom : ${res.data.name}`);
    } else {
      console.error(`\n❌ Erreur (HTTP ${res.status}):`);
      console.error(JSON.stringify(res.data, null, 2));
      process.exit(1);
    }
  } catch (err) {
    console.error("\n❌ Erreur réseau:", err.message);
    process.exit(1);
  }

  getRL().close();
}

// ── Point d'entrée ────────────────────────────────────────────────────────────

async function main() {
  loadBackendEnv();

  const args = process.argv.slice(2);
  const fileIndex = args.indexOf("--file");

  if (fileIndex !== -1) {
    const filePath = args[fileIndex + 1];
    if (!filePath) {
      console.error(
        "❌ Argument --file manquant. Usage : --file <chemin/vers/batch.json>",
      );
      process.exit(1);
    }
    await runBatch(filePath);
  } else {
    await runInteractive();
  }
}

main().catch((err) => {
  console.error("❌ Erreur inattendue:", err.message);
  process.exit(1);
});
