import { parseLegacyJson } from "../../migration/migrator.js"

const MIGRATION_TEMPLATE = "systems/fvtt-chroniques-de-l-etrange/templates/apps/cde-migration-app.html"

/**
 * Dialog for importing legacy CDE actor JSON files into the current system.
 *
 * Accessible via the System Settings menu (registerMenu).
 * Supports multi-file selection and shows a preview table before importing.
 */
export class CDEMigrationApp extends foundry.applications.api.HandlebarsApplicationMixin(
  foundry.applications.api.ApplicationV2
) {
  static DEFAULT_OPTIONS = {
    id:      "cde-migration-app",
    classes: ["cde-migration-app"],
    tag:     "div",
    window: {
      title:     "CDE.MigrationTitle",
      icon:      "fas fa-file-import",
      resizable: false,
    },
    position: { width: 600, height: "auto" },
    actions: {
      clearFiles:    CDEMigrationApp.#clearFiles,
      doImport:      CDEMigrationApp.#doImport,
      confirmImport: CDEMigrationApp.#confirmImport,
      cancelImport:  CDEMigrationApp.#cancelImport,
    },
  }

  static PARTS = {
    form: { template: MIGRATION_TEMPLATE },
  }

  /** @type {Array<{name: string, type: string, img: string, system: object, items: object[], _srcFile: string}>} */
  #pending = []

  /** @type {string[]} - error messages per file */
  #errors = []

  /** @type {"idle"|"confirm"|"importing"} */
  #importState = "idle"

  /** @type {number} - actors created so far (during importing) */
  #progress = 0

  async _prepareContext(options) {
    // Compute _duplicate live from the world each render, to avoid stale flags
    const enrichDuplicate = (a) => ({
      ...a,
      _duplicate: game.actors?.getName(a.name) !== null,
    })
    const pending = this.#pending.map(enrichDuplicate)
    const duplicateCount = pending.filter(a => a._duplicate).length
    return {
      pending,
      errors:     this.#errors,
      hasPending: this.#pending.length > 0,
      hasErrors:  this.#errors.length > 0,
      hasDuplicates: duplicateCount > 0,
      duplicateCount,
      count:      this.#pending.length,
      importState: this.#importState,
      progress:   this.#progress,
      total:      this.#pending.length,
    }
  }

  /** After render, wire up the file input. */
  _onRender(context, options) {
    super._onRender(context, options)
    const input = this.element.querySelector(".cde-migration-file-input")
    input?.addEventListener("change", this.#onFileChange.bind(this))

    const dropZone = this.element.querySelector(".cde-migration-drop-zone")
    if (dropZone) {
      dropZone.addEventListener("dragover", (e) => { e.preventDefault(); dropZone.classList.add("is-dragover") })
      dropZone.addEventListener("dragleave", () => dropZone.classList.remove("is-dragover"))
      dropZone.addEventListener("drop", (e) => {
        e.preventDefault()
        dropZone.classList.remove("is-dragover")
        this.#processFiles(Array.from(e.dataTransfer.files))
      })
    }
  }

  async #onFileChange(event) {
    const files = Array.from(event.target.files ?? [])
    event.target.value = ""
    await this.#processFiles(files)
  }

  async #processFiles(files) {
    for (const file of files) {
      if (!file.name.endsWith(".json")) {
        this.#errors.push(game.i18n.format("CDE.MigrationErrorNotJson", { file: file.name }))
        continue
      }
      try {
        const text = await file.text()
        const actors = parseLegacyJson(text)
        for (const actor of actors) {
          actor._srcFile = file.name
          // Avoid duplicates-by-name in our pending list
          if (this.#pending.some(p => p.name === actor.name)) {
            this.#errors.push(`« ${actor.name} » ignoré (nom déjà dans la liste d'attente, fichier « ${file.name} »)`)
            continue
          }
          this.#pending.push(actor)
        }
      } catch (err) {
        this.#errors.push(game.i18n.format("CDE.MigrationErrorParse", { file: file.name, error: err.message }))
      }
    }
    this.#importState = "idle"
    this.render()
  }

  static async #clearFiles() {
    this.#pending = []
    this.#errors = []
    this.#importState = "idle"
    this.#progress = 0
    this.render()
  }

  /** First click: switch to confirmation state instead of importing immediately. */
  static async #doImport() {
    if (!this.#pending.length) return
    this.#importState = "confirm"
    this.render()
  }

  /** Second click: actually perform the import. */
  static async #confirmImport() {
    if (!this.#pending.length) return

    this.#importState = "importing"
    this.#progress = 0
    this.render()

    const total = this.#pending.length
    const created = []
    const failed  = []

    for (let i = 0; i < total; i++) {
      const data = this.#pending[i]
      try {
        const { _srcFile, ...actorData } = data
        const actor = await Actor.create(actorData)
        created.push(actor.name)
      } catch (err) {
        failed.push(`${data.name}: ${err.message}`)
        console.error(`CHRONIQUESDELETRANGE | Import failed for "${data.name}":`, err)
      }
      this.#progress = i + 1
      // Live-update the progress element in the DOM without full re-render
      const progEl = this.element?.querySelector(".cde-migration-progress-count")
      if (progEl) progEl.textContent = `${this.#progress}/${total}`
    }

    this.#pending = []
    this.#errors = failed
    this.#importState = "idle"
    this.#progress = 0
    this.render()

    if (created.length) {
      ui.notifications.info(
        game.i18n.format("CDE.MigrationSuccess", { count: created.length, names: created.join(", ") })
      )
    }
    if (failed.length) {
      ui.notifications.warn(
        game.i18n.format("CDE.MigrationPartialError", { count: failed.length })
      )
    }
  }

  static async #cancelImport() {
    this.#importState = "idle"
    this.render()
  }
}
