/**
 * HouseHub - Test Engine 🦙
 * Moteur de tests automatisés (E2E) - Version Anti-Flakiness & QA Exhaustive
 */

const PachaTestEngine = {
  arena: document.getElementById("test-arena"),
  reportBox: document.getElementById("test-report"),
  doc: null,

  // ==========================================
  // 🛠️ HELPERS (BLINDÉS POUR LE QA)
  // ==========================================

  wait: (ms) => new Promise((r) => setTimeout(r, ms)),

  log: function (msg, icon = "ℹ️") {
    this.reportBox.value += `[${new Date().toLocaleTimeString()}] ${icon} ${msg}\n`;
    this.reportBox.scrollTop = this.reportBox.scrollHeight;
  },

  assert: function (cond, msgPass, msgFail) {
    this.log(cond ? msgPass : msgFail || msgPass, cond ? "✅" : "❌");
  },

  // 📡 Intercepte les erreurs de l'application dans l'iframe pour les afficher dans le rapport
  injectIframeErrorCatcher: function () {
    if (!this.arena.contentWindow) return;

    this.arena.contentWindow.onerror = (msg, url, line) => {
      this.log(`Erreur App (Ligne ${line}): ${msg}`, "🔥");
    };

    const origError = this.arena.contentWindow.console.error;
    this.arena.contentWindow.console.error = (...args) => {
      this.log(`Console Error: ${args.join(" ")}`, "🔥");
      origError.apply(this.arena.contentWindow.console, args);
    };
  },

  // 🛡️ Attend le rechargement de la page de manière stricte
  actionAndWaitForReload: async function (actionFn, timeout = 5000) {
    return new Promise((resolve, reject) => {
      let reloaded = false;

      this.arena.onload = () => {
        reloaded = true;
        this.doc = this.arena.contentWindow.document;
        this.arena.contentWindow.confirm = () => true;
        this.arena.contentWindow.alert = () => true;
        this.injectIframeErrorCatcher();
        resolve();
      };

      // Exécute l'action et gère le rejet si elle plante
      Promise.resolve(actionFn()).catch((err) => reject(err));

      setTimeout(() => {
        if (!reloaded) {
          this.log(
            "⚠️ Le rechargement n'a pas eu lieu. Suite du test...",
            "⏱️",
          );
          resolve();
        }
      }, timeout);
    });
  },

  load: async function (url) {
    this.log(`Chargement de la page : ${url}`, "🔄");
    return new Promise((resolve) => {
      this.arena.onload = () => {
        this.doc = this.arena.contentWindow.document;
        this.arena.contentWindow.confirm = () => true;
        this.arena.contentWindow.alert = () => true;
        this.injectIframeErrorCatcher();
        resolve();
      };
      this.arena.src = url;
    });
  },

  get: function (sel) {
    return this.doc.querySelector(sel);
  },

  // 🖱️ Clic strict : Si l'élément n'existe pas, on DÉCLENCHE UNE ERREUR FATALE
  click: async function (sel, delay = 500) {
    const el = typeof sel === "string" ? this.get(sel) : sel;
    if (!el) {
      throw new Error(
        `Clic impossible : l'élément '${typeof sel === "string" ? sel : "DOM Object"}' est introuvable.`,
      );
    }

    this.arena.contentWindow.confirm = () => true;
    this.arena.contentWindow.alert = () => true;
    el.click();
    await this.wait(delay);
    return true;
  },

  fill: function (sel, val) {
    const el = this.get(sel);
    if (!el) throw new Error(`Remplissage impossible : '${sel}' introuvable.`);
    el.value = val;
  },

  select: async function (sel, val, delay = 300) {
    const el = this.get(sel);
    if (!el) throw new Error(`Sélection impossible : '${sel}' introuvable.`);
    el.value = val;
    el.dispatchEvent(new Event("change"));
    await this.wait(delay);
  },

  findInTable: function (text) {
    return Array.from(this.doc.querySelectorAll("td")).find((el) =>
      el.textContent.includes(text),
    );
  },

  // ==========================================
  // 🧪 SCÉNARIO EXHAUSTIF : SUIVI MENSUEL (MODALES & CRUD)
  // ==========================================
  testBudgetSuiviExhaustive: async function () {
    this.reportBox.value = "";
    this.log("=== 🚀 DÉBUT EXHAUSTIF : SUIVI MENSUEL ===", "INFO");

    await this.load("budget.php?tab=suivi");
    await this.wait(1000);

    // --- 1. GESTION DE L'ÉTAT (CLÔTURE / RÉOUVERTURE) ---
    this.log("🔍 Test 1 : État du mois (Clôture / Réouverture)");
    let btnReopenInitial = this.get(
      'form input[value="reopen_month"] ~ button[type="submit"]',
    );
    if (btnReopenInitial) {
      this.log(
        "🔒 Mois actuellement fermé. Réouverture forcée pour les tests...",
        "WARN",
      );
      await this.actionAndWaitForReload(
        async () => await this.click(btnReopenInitial),
      );
      await this.wait(1500); // ⏱️ Attente de la 2e redirection JS du PHP
      this.assert(
        this.get('form input[value="close_month"]') !== null,
        "Mois rouvert.",
      );
    }

    // --- 2. UI TOGGLES ---
    this.log("🔍 Test 2 : Toggle 'Charges à venir'");
    const toggleBtn = this.get(
      "button[onclick*=\"toggleDiv('pendingDetailsList')\"]",
    );
    if (toggleBtn) {
      await this.click(toggleBtn);
      const pendingList = this.get("#pendingDetailsList");
      this.assert(
        pendingList && pendingList.style.display !== "none",
        "Liste des charges déployée.",
      );
    }

    // --- 3. MODALE CSV ---
    this.log("🔍 Test 3 : Modale Import CSV");
    const btnCsv = this.get('button[onclick*="importCsvModal"]');
    if (btnCsv) {
      await this.click(btnCsv);
      const csvModal = this.get("#importCsvModal");
      this.assert(
        csvModal &&
          (csvModal.classList.contains("is-open") ||
            csvModal.style.display === "flex"),
        "Modale CSV ouverte.",
      );

      // Fermeture
      const closeCsvBtn = csvModal.querySelector(
        ".pf-modal-close, button[onclick*='closeSuiviModal']",
      );
      if (closeCsvBtn) await this.click(closeCsvBtn);
      this.assert(
        !csvModal.classList.contains("is-open") &&
          csvModal.style.display !== "flex",
        "Modale CSV fermée.",
      );
    }

    // --- 4. MODALE SNAPSHOT (UPDATE BALANCE) ---
    this.log("🔍 Test 4 : Modale Snapshot (Solde Bancaire)");
    const btnSnapshot = this.get('button[onclick*="snapshotModal"]');
    if (btnSnapshot) {
      await this.click(btnSnapshot);
      this.assert(this.get("#snapshotModal"), "Modale Snapshot ouverte.");

      this.fill('#snapshotModal input[name="snapshot_amount"]', "1337.00");
      this.log("Soumission du nouveau solde...", "INFO");
      await this.actionAndWaitForReload(async () => {
        await this.click('#snapshotModal button[type="submit"]');
      });

      const pageText = this.doc.body.innerText;
      this.assert(
        pageText.includes("1 337"),
        "Solde mis à jour et formaté à 1 337 €.",
      );
    }

    // --- 5. CRUD DÉPENSE (AJOUT / ÉDITION / SUPPRESSION) ---
    this.log("🔍 Test 5 : CRUD Dépense Manuelle");
    const btnAdd = this.get(".btn-add-item");

    if (btnAdd) {
      // 5A. AJOUT
      this.log("Création d'une nouvelle dépense...");
      await this.click(btnAdd);
      await this.select("#modalCatSelect", "Autres");
      this.fill("#modalAmount", "77.77");
      this.fill("#modalLabelInput", "E2E_QA_TEST_EXPENSE");

      await this.actionAndWaitForReload(async () => {
        await this.click('#manualExpenseModal button[type="submit"]');
      });

      let newExpense = this.findInTable("E2E_QA_TEST_EXPENSE");
      this.assert(
        newExpense !== undefined,
        "Dépense 'E2E_QA_TEST_EXPENSE' trouvée dans le DOM.",
      );

      if (newExpense) {
        // 5B. ÉDITION
        this.log("✏️ Édition de la dépense...");
        const row = newExpense.closest("tr");

        // 🛡️ NOUVEAU : Sécurité anti-crash
        if (!row) {
          throw new Error(
            "L'élément trouvé n'est pas dans une ligne de tableau (<tr> manquant). Le test est corrompu.",
          );
        }

        const btnEdit = row.querySelector('button[onclick*="openEditModal"]');
        if (btnEdit) {
          await this.click(btnEdit);
          this.fill("#modalAmount", "88.88");
          await this.actionAndWaitForReload(async () => {
            await this.click('#manualExpenseModal button[type="submit"]');
          });

          const editedExpense = this.findInTable("E2E_QA_TEST_EXPENSE");
          this.assert(
            editedExpense &&
              editedExpense.closest("tr").innerHTML.includes("88"),
            "Montant mis à jour à 88.88€.",
          );
        }

        // 5C. SUPPRESSION (Gère pachaConfirm custom modal)
        this.log("🧹 Teardown : Suppression de la dépense...");
        const rowToDel = this.findInTable("E2E_QA_TEST_EXPENSE").closest("tr");
        const btnDel = rowToDel.querySelector("button.delete");

        if (btnDel) {
          await this.actionAndWaitForReload(async () => {
            await this.click(btnDel); // Déclenche pachaConfirm
            await this.wait(500); // Attend l'animation de la modale custom

            const confirmBtn = this.get("#confirm-ok");
            if (confirmBtn) {
              await this.click(confirmBtn); // Valide la suppression (fetch AJAX)
            }
          }, 3000);

          const checkGone = this.findInTable("E2E_QA_TEST_EXPENSE");
          this.assert(
            checkGone === undefined,
            "Base de données propre ! Dépense supprimée.",
          );
        }
      }
    } else {
      this.log("Bouton '.btn-add-item' introuvable.", "❌");
    }

    // --- 6. CLÔTURE ET RÉOUVERTURE DU MOIS (TEARDOWN STATE) ---
    this.log("🔍 Test 6 : Clôture du mois");
    let btnClose = this.get(
      'form input[value="close_month"] ~ button[type="submit"]',
    );
    if (btnClose) {
      this.log("Verrouillage du mois...");
      await this.actionAndWaitForReload(async () => await this.click(btnClose));
      await this.wait(1500); // ⏱️ Attente de la 2e redirection JS du PHP (Mois suivant)

      this.log("Retour au mois précédent pour vérification...");
      await this.actionAndWaitForReload(
        async () =>
          await this.click(".suivi-nav-group a.suivi-btn-nav:first-child"),
      );

      this.assert(
        this.get('form input[value="reopen_month"]') !== null,
        "Mois clôturé avec succès.",
      );

      // Teardown
      this.log("🧹 Teardown : Restauration du mois (Réouverture)");
      await this.actionAndWaitForReload(
        async () =>
          await this.click(
            'form input[value="reopen_month"] ~ button[type="submit"]',
          ),
      );
      await this.wait(1500); // ⏱️ Attente de la 2e redirection JS du PHP

      this.assert(
        this.get('form input[value="close_month"]') !== null,
        "Mois rouvert avec succès.",
      );
    }

    this.log("=== 🏁 FIN DU SCÉNARIO EXHAUSTIF ===", "INFO");
  },

  // ==========================================
  // 🧪 SCÉNARIO 2 : BUDGET PRÉVISIONNEL
  // ==========================================
  testBudgetPrev: async function () {
    this.reportBox.value = "";
    this.log("=== 🚀 DÉBUT DU SCÉNARIO : BUDGET PRÉVISIONNEL ===", "INFO");

    await this.load("budget.php?tab=budget_prev");
    await this.wait(1000);

    this.log("🔍 Étape 1 : Test du mode Somme flottant...", "INFO");
    await this.click("#fabSumMode");
    this.assert(
      this.doc.body.classList.contains("sum-mode-active"),
      "Le mode somme s'active.",
    );

    const firstSalaryInput = this.get('input[data-field="salary"]');
    if (firstSalaryInput) {
      await this.click(firstSalaryInput, 500);
      const sumValue = this.get("#sumResultValue").innerText;
      this.assert(
        sumValue !== "0,00 €" && sumValue !== "0 €",
        `Le total interactif affiche : ${sumValue}`,
      );
    }

    await this.click(".pf-sum-close");
    this.assert(
      !this.doc.body.classList.contains("sum-mode-active"),
      "Le mode somme se désactive.",
    );

    this.log("🔍 Étape 2 : Test de sauvegarde de la note...", "INFO");
    const noteArea = this.get("#monthNoteArea");
    if (noteArea) {
      const oldNote = noteArea.value;
      this.fill("#monthNoteArea", "🤖 Test Auto");
      await this.click('button[onclick^="saveGenericNote"]', 1500);

      const indicator = this.get("#note-save-indicator");
      this.assert(indicator !== null, "Indicateur de sauvegarde affiché.");

      this.fill("#monthNoteArea", oldNote);
      await this.click('button[onclick^="saveGenericNote"]', 500);
    }

    const uniqueCatName = "TEST_CAT_" + Math.floor(Math.random() * 10000);
    this.log(
      `🔍 Étape 3 : Création de la catégorie '${uniqueCatName}'...`,
      "INFO",
    );

    await this.click('button[onclick*="addCatModal"]');
    this.fill('#addCatModal input[name="name"]', uniqueCatName);
    await this.select('#addCatModal select[name="target"]', "vers commune");

    await this.actionAndWaitForReload(async () => {
      await this.click('#addCatModal button[type="submit"]');
    });

    const newCatCell = Array.from(
      this.doc.querySelectorAll(".prev-alloc-table td, .prev-alloc-table div"),
    ).find((el) => el.textContent.includes(uniqueCatName));
    this.assert(
      newCatCell !== undefined,
      `SUCCÈS : '${uniqueCatName}' insérée !`,
    );

    if (newCatCell) {
      this.log("🧹 Étape 4 : Nettoyage de la BDD...", "WARN");
      const row = newCatCell.closest("tr");
      const delBtn = row.querySelector(".delete");

      if (delBtn) {
        await this.actionAndWaitForReload(async () => {
          await this.click(delBtn);
        });

        const checkGone = Array.from(
          this.doc.querySelectorAll(".prev-alloc-table td"),
        ).find((td) => td.textContent.includes(uniqueCatName));
        this.assert(
          checkGone === undefined,
          "NETTOYAGE PARFAIT : Ligne effacée.",
        );
      }
    }

    this.log("=== 🏁 FIN DU SCÉNARIO ===", "INFO");
  },
};

// ==========================================
// ROUTEUR DU LABORATOIRE ET BOUTON COPIER
// ==========================================
document.getElementById("btn-run-test")?.addEventListener("click", async () => {
  const selectedTest = document.getElementById("test-selector").value;
  const btnRun = document.getElementById("btn-run-test");

  btnRun.disabled = true;
  btnRun.style.opacity = "0.5";

  try {
    switch (selectedTest) {
      case "budget_suivi_exhaustive":
        await PachaTestEngine.testBudgetSuiviExhaustive();
        break;
      case "budget_prev":
        await PachaTestEngine.testBudgetPrev();
        break;
      default:
        PachaTestEngine.log(`Scénario non implémenté : ${selectedTest}`, "⚠️");
    }
  } catch (error) {
    PachaTestEngine.log(`Erreur JS critique : ${error.message}`, "❌");
    console.error(error);
  }

  btnRun.disabled = false;
  btnRun.style.opacity = "1";
});

// 📋 Bouton "Copier"
document
  .getElementById("btn-copy-report")
  ?.addEventListener("click", async () => {
    const textArea = document.getElementById("test-report");
    const reportText = textArea.value;
    const successMsg = window.I18N
      ? window.I18N.tests_report_copied || "Rapport copié !"
      : "Rapport copié !";

    try {
      if (navigator.clipboard && window.isSecureContext) {
        await navigator.clipboard.writeText(reportText);
        alert(successMsg);
      } else {
        textArea.select();
        document.execCommand("copy");
        window.getSelection().removeAllRanges();
        alert(successMsg);
      }
    } catch (err) {
      alert("Erreur lors de la copie du rapport.");
      console.error(err);
    }
  });
