import type { CommandBus } from '@application/handlers/CommandBus';
import type { QueryBus } from '@application/handlers/QueryBus';
import { GEN_COLORS, RACE_GEN, RACES_DATA } from '@domain/value-objects/Race';
import { simulateStock, type SimulationCrossing } from '@domain/services/StockSimulator';
import { getDDImage } from '@presentation/helpers/dd-image';
import { esc } from '@presentation/helpers/format';

interface StockEntry {
  m: number;
  f: number;
}

export class InventaireView {
  private el: HTMLElement | null = null;
  private genFilter = 0;
  private search = '';
  private inventaire: Record<string, StockEntry> = {};
  private calcResults: SimulationCrossing[] | null = null;
  private unusedStock: { race: string; m: number; f: number }[] | null = null;

  constructor(
    private commandBus: CommandBus,
    private queryBus: QueryBus,
  ) {}

  render(container: HTMLElement): void {
    this.el = document.createElement('div');
    this.el.className = 'inv-view-new';
    container.appendChild(this.el);

    const stored = this.queryBus.execute<Record<string, StockEntry>>({ type: 'get-inventaire' });
    if (stored && typeof stored === 'object') {
      this.inventaire = { ...stored };
    }

    this.updateDOM();
  }

  update(): void {}

  destroy(): void {
    this.saveInventaire();
    this.el?.remove();
    this.el = null;
  }

  private getStock(race: string): StockEntry {
    if (!this.inventaire[race]) this.inventaire[race] = { m: 0, f: 0 };
    return this.inventaire[race];
  }

  private totalStock(): { total: number; races: number } {
    let total = 0, races = 0;
    for (const v of Object.values(this.inventaire)) {
      const sum = (v.m || 0) + (v.f || 0);
      if (sum > 0) { total += sum; races++; }
    }
    return { total, races };
  }

  private saveInventaire(): void {
    this.commandBus.execute({ type: 'update-settings', inventaire: { ...this.inventaire } });
  }

  private updateDOM(): void {
    if (!this.el) return;

    if (this.calcResults !== null) {
      this.renderResultsView();
    } else {
      this.renderInventoryView();
    }
  }

  private renderInventoryView(): void {
    if (!this.el) return;
    const { genFilter, search } = this;

    const allRaces: { name: string; gen: number }[] = [];
    for (const base of ['Rousse', 'Amande', 'Dorée']) allRaces.push({ name: base, gen: 1 });
    for (const [g, rs] of Object.entries(RACES_DATA)) {
      for (const r of rs) allRaces.push({ name: r.name, gen: parseInt(g) });
    }

    const q = search.trim().toLowerCase();
    const filtered = allRaces.filter(r =>
      (genFilter > 0 ? r.gen === genFilter : true) &&
      (q ? r.name.toLowerCase().includes(q) : true)
    );
    const { total } = this.totalStock();

    let html = '';

    /* ── Header ── */
    html += `<div class="inv-header">
      <div>
        <h2 class="inv-title">Inventaire Actuel</h2>
        <div class="reappro-title-bar"></div>
      </div>
      <span class="inv-total" id="inv-summary">${total} Dragons au total</span>
    </div>`;

    /* ── Search + Gen chips + Action buttons ── */
    html += `<div class="inv-filters">
      <div class="inv-filters-row">
        <div class="inv-search-col">
          <label class="inv-filter-label">Rechercher une Dragodinde</label>
          <div class="accoup-search-wrap">
            <input class="accoup-search" id="inv-search-input" type="text"
              placeholder="Nom du type…" value="${esc(search)}" autocomplete="off">
            ${search ? `<button class="accoup-search-clear" title="Effacer"><span class="material-symbols-outlined" style="font-size:16px">close</span></button>` : ''}
          </div>
        </div>
        <div class="inv-gen-col">
          <label class="inv-filter-label">Filtrer par Génération</label>
          <div class="accoup-gen-chips" style="margin-bottom:0;border-bottom:none;padding-bottom:0">
            <button class="accoup-gen-chip${genFilter === 0 ? ' active' : ''}" data-gen="0">Toutes</button>`;
    for (let g = 1; g <= 10; g++) {
      html += `<button class="accoup-gen-chip${genFilter === g ? ' active' : ''}" data-gen="${g}">Gen ${g}</button>`;
    }
    html += `</div>
        </div>
      </div>
      <div class="inv-actions">
        <button class="inv-btn-reset" id="inv-reset">
          <span class="material-symbols-outlined" style="font-size:16px">restart_alt</span>
          Réinitialiser
        </button>
        <button class="inv-btn-calc" id="inv-calc">
          <span class="material-symbols-outlined" style="font-size:16px">science</span>
          Calculer
        </button>
      </div>
    </div>`;

    /* ── Race grid ── */
    if (filtered.length === 0) {
      html += `<div class="accoup-empty">Aucune race trouvée</div>`;
    } else {
      html += `<div class="inv-grid">`;
      for (const race of filtered) {
        const stock = this.getStock(race.name);
        const genCol = GEN_COLORS[race.gen] ?? '#888';
        html += `<div class="inv-card-new">
          <span class="inv-gen-badge" style="color:${genCol};border-color:${genCol}30;background:${genCol}15">GEN ${race.gen}</span>
          <div class="inv-avatar">
            ${getDDImage(race.name)}
          </div>
          <h4 class="inv-card-name-new">${esc(race.name)}</h4>
          <div class="inv-gender-row">
            <div class="inv-gender-input male">
              <span class="inv-gender-symbol">♂</span>
              <input type="number" min="0" value="${stock.m}" data-race="${esc(race.name)}" data-gender="m">
            </div>
            <div class="inv-gender-input female">
              <span class="inv-gender-symbol">♀</span>
              <input type="number" min="0" value="${stock.f}" data-race="${esc(race.name)}" data-gender="f">
            </div>
          </div>
        </div>`;
      }
      html += `</div>`;
    }

    this.el.innerHTML = html;
    this.bindInventoryEvents();

    if (search) {
      const inp = this.el.querySelector<HTMLInputElement>('#inv-search-input');
      if (inp) { inp.focus(); inp.setSelectionRange(inp.value.length, inp.value.length); }
    }
  }

  private renderResultsView(): void {
    if (!this.el) return;
    let html = '';

    /* Back button */
    html += `<div class="reappro-top-bar">
      <button class="reappro-back-btn" id="inv-back">
        <span class="material-symbols-outlined" style="font-size:18px">arrow_back</span>
        Retour à l'inventaire
      </button>
    </div>`;

    html += this.renderCalcResults();

    this.el.innerHTML = html;
    this.bindResultsEvents();
  }

  private renderCalcResults(): string {
    const crossings = this.calcResults!;

    if (crossings.length === 0) {
      return `<div class="inv-calc-empty">
        <span class="material-symbols-outlined" style="font-size:48px;color:var(--md-outline-variant)">egg</span>
        <p>Aucun croisement possible avec le stock actuel.</p>
      </div>`;
    }

    // Group by gen
    const byGen = new Map<number, SimulationCrossing[]>();
    for (const c of crossings) {
      if (!byGen.has(c.gen)) byGen.set(c.gen, []);
      byGen.get(c.gen)!.push(c);
    }
    const gens = Array.from(byGen.keys()).sort((a, b) => a - b);
    const totalBabies = crossings.reduce((s, c) => s + c.count, 0);

    let html = '';

    /* Glass panel wrapper */
    html += `<div class="inv-calc-panel">`;

    /* Panel header */
    html += `<div class="inv-calc-header">
      <div class="inv-calc-header-left">
        <span class="material-symbols-outlined inv-calc-icon">science</span>
        <h2 class="inv-calc-title">Calculateur de Croisements</h2>
      </div>
      <div class="inv-calc-stats">
        <span class="inv-calc-stat-value">${totalBabies}</span>
        <span class="inv-calc-stat-label">bébés possibles sur ${gens.length} génération${gens.length > 1 ? 's' : ''}</span>
      </div>
    </div>`;

    /* Crossings by gen */
    for (let gi = 0; gi < gens.length; gi++) {
      const g = gens[gi];
      const gCrossings = byGen.get(g)!;
      const genTotal = gCrossings.reduce((s, c) => s + c.count, 0);
      const genCol = GEN_COLORS[g] ?? '#888';

      html += `<div class="inv-calc-step">
        <div class="inv-calc-step-label">
          <div class="inv-calc-step-badge-col">
            <span class="inv-calc-step-num" style="background:${genCol}">0${gi + 1}</span>
            <span class="inv-calc-step-subtitle">Étape</span>
          </div>
          <h3 class="inv-calc-step-title">Génération ${g}</h3>
          <span class="inv-calc-step-count">${genTotal} bébé${genTotal > 1 ? 's' : ''}</span>
        </div>`;

      for (const c of gCrossings) {
        html += `<div class="inv-calc-crossing">`;

        // Parent A
        html += this.renderCalcParent(c.parentA, c.pAMale, c.pAFemale);
        html += `<span class="material-symbols-outlined reappro-crossing-op">add</span>`;
        // Parent B
        html += this.renderCalcParent(c.parentB, c.pBMale, c.pBFemale);
        html += `<span class="material-symbols-outlined reappro-crossing-op" style="color:var(--md-primary)">arrow_forward</span>`;
        // Baby
        const babyGen = RACE_GEN[c.baby] ?? 0;
        html += `<div class="inv-calc-baby">
          <div class="inv-calc-baby-avatar">
            ${getDDImage(c.baby)}
            <span class="reappro-baby-gen-badge" style="background:${genCol}">G${babyGen}</span>
          </div>
          <span class="inv-calc-baby-name">${esc(c.baby)}</span>
          <span class="inv-calc-baby-qty">&times;${c.count}</span>
        </div>`;

        html += `</div>`; // .inv-calc-crossing
      }

      html += `</div>`; // .inv-calc-step
    }

    /* Save workflow button */
    html += `<div class="inv-calc-save-row">
      <button class="reappro-save-btn" id="inv-save">
        <span class="material-symbols-outlined" style="font-size:18px">save</span>
        Sauvegarder le workflow
      </button>
    </div>`;

    html += `</div>`; // .inv-calc-panel

    /* Unused stock */
    if (this.unusedStock && this.unusedStock.length > 0) {
      html += `<div class="inv-unused-section">
        <div class="inv-unused-header">
          <h3 class="inv-unused-title">Dragodindes Restantes</h3>
        </div>
        <div class="inv-unused-grid">`;
      for (const u of this.unusedStock) {
        const gen = RACE_GEN[u.race] ?? 1;
        html += `<div class="inv-unused-card">
            <div class="inv-unused-avatar">
              ${getDDImage(u.race)}
            </div>
            <div class="inv-unused-info">
              <p class="inv-unused-name">${esc(u.race)}</p>
              <p class="inv-unused-qty">
                ${u.m > 0 ? `<span style="color:#50a0ff;font-weight:800">♂ ${u.m}</span>` : ''}
                ${u.f > 0 ? `<span style="color:#ff64a0;font-weight:800">♀ ${u.f}</span>` : ''}
              </p>
            </div>
          </div>`;
      }
      html += `</div></div>`;
    }

    return html;
  }

  private renderCalcParent(race: string, maleUsed: number, femaleUsed: number): string {
    const parts: string[] = [];
    if (maleUsed > 0) parts.push(`<span style="color:#50a0ff">♂ ${maleUsed}</span>`);
    if (femaleUsed > 0) parts.push(`<span style="color:#ff64a0">♀ ${femaleUsed}</span>`);
    return `<div class="inv-calc-parent">
      <div class="inv-calc-parent-avatar">
        ${getDDImage(race)}
      </div>
      <span class="inv-calc-parent-name">${esc(race)}</span>
      <span class="inv-calc-parent-gender">${parts.join(' ')}</span>
    </div>`;
  }

  private bindInventoryEvents(): void {
    if (!this.el) return;

    // Search
    const searchInput = this.el.querySelector<HTMLInputElement>('#inv-search-input');
    if (searchInput) {
      searchInput.addEventListener('input', () => { this.search = searchInput.value; this.updateDOM(); });
    }
    const clearBtn = this.el.querySelector('.accoup-search-clear');
    if (clearBtn) {
      clearBtn.addEventListener('click', () => { this.search = ''; this.updateDOM(); });
    }

    // Gen filter chips
    this.el.querySelectorAll('.accoup-gen-chip[data-gen]').forEach(btn => {
      btn.addEventListener('click', () => {
        this.genFilter = parseInt((btn as HTMLElement).dataset.gen ?? '0');
        this.updateDOM();
      });
    });

    // Stock inputs — focus/blur
    this.el.querySelectorAll('.inv-gender-input input').forEach(inp => {
      const el = inp as HTMLInputElement;
      let prev = el.value;
      el.addEventListener('focus', () => { prev = el.value; el.value = ''; });
      el.addEventListener('input', () => {
        if (el.value === '') return;
        const race = el.dataset.race!;
        const gender = el.dataset.gender as 'm' | 'f';
        if (!this.inventaire[race]) this.inventaire[race] = { m: 0, f: 0 };
        this.inventaire[race][gender] = Math.max(0, parseInt(el.value) || 0);
        const { total } = this.totalStock();
        const summary = this.el?.querySelector('#inv-summary');
        if (summary) summary.textContent = `${total} Dragons au total`;
      });
      el.addEventListener('blur', () => {
        if (el.value === '') el.value = prev;
        const race = el.dataset.race!;
        const gender = el.dataset.gender as 'm' | 'f';
        if (!this.inventaire[race]) this.inventaire[race] = { m: 0, f: 0 };
        this.inventaire[race][gender] = Math.max(0, parseInt(el.value) || 0);
        el.value = String(this.inventaire[race][gender]);
        this.saveInventaire();
        const { total } = this.totalStock();
        const summary = this.el?.querySelector('#inv-summary');
        if (summary) summary.textContent = `${total} Dragons au total`;
      });
    });

    // Reset
    const resetBtn = this.el.querySelector('#inv-reset');
    if (resetBtn) {
      resetBtn.addEventListener('click', () => {
        this.inventaire = {};
        this.calcResults = null;
        this.unusedStock = null;
        this.saveInventaire();
        this.updateDOM();
      });
    }

    // Calculate
    const calcBtn = this.el.querySelector('#inv-calc');
    if (calcBtn) {
      calcBtn.addEventListener('click', () => {
        this.calcInventaire();
        this.updateDOM();
      });
    }
  }

  private bindResultsEvents(): void {
    if (!this.el) return;

    // Back button — retour à l'inventaire sans réinitialiser
    const backBtn = this.el.querySelector('#inv-back');
    if (backBtn) {
      backBtn.addEventListener('click', () => {
        this.calcResults = null;
        this.unusedStock = null;
        this.updateDOM();
      });
    }

    // Save workflow
    const saveBtn = this.el.querySelector<HTMLButtonElement>('#inv-save');
    if (saveBtn && this.calcResults && this.calcResults.length > 0) {
      saveBtn.addEventListener('click', () => {
        const crossings = this.calcResults!;
        const topCrossing = crossings.reduce((best, c) => c.gen > best.gen ? c : best, crossings[0]);
        const target = topCrossing.baby;
        const qty = topCrossing.count;
        const materials = Object.entries(this.inventaire)
          .filter(([, e]) => e.m > 0 || e.f > 0)
          .map(([race, e]) => ({ race, m: e.m, f: e.f }));
        const steps = crossings.map(c => ({
          baby: c.baby,
          parentA: c.parentA,
          parentB: c.parentB,
          couples: c.count,
          gen: c.gen,
        }));

        this.commandBus.execute({
          type: 'save-workflow',
          target,
          qty,
          materials,
          steps,
          repro: {},
        });

        saveBtn.innerHTML = '<span class="material-symbols-outlined" style="font-size:18px">check</span> Sauvegardé !';
        setTimeout(() => {
          saveBtn.innerHTML = '<span class="material-symbols-outlined" style="font-size:18px">save</span> Sauvegarder le workflow';
        }, 2000);
      });
    }
  }

  /* ── Simulation ── */
  private calcInventaire(): void {
    const { crossings, unusedStock } = simulateStock(this.inventaire);
    this.calcResults = crossings;
    this.unusedStock = unusedStock;
  }
}
