import type { CommandBus } from '@application/handlers/CommandBus';
import type { QueryBus } from '@application/handlers/QueryBus';
import type { UIState } from '@presentation/state/UIState';
import type { WorkflowItem } from '@application/queries/GetWorkflows';
import type { ImportWorkflowsCommand } from '@application/commands/ImportWorkflows';
import { GEN_COLORS, RACE_GEN, raceColor } from '@domain/value-objects/Race';
import { getDDImage } from '@presentation/helpers/dd-image';
import { esc } from '@presentation/helpers/format';
import { Toast } from './Toast';
import { ConfirmModal } from './ConfirmModal';
import { UndoManager } from '@presentation/services/UndoManager';

interface WorkflowProgress {
  done: number;
  total: number;
  pct: number;
}

function getProgress(wf: WorkflowItem): WorkflowProgress {
  let done = 0;
  let total = 0;
  wf.materials.forEach(m => {
    total += m.needed;
    done += Math.min(m.done, m.needed);
  });
  wf.steps.forEach(st =>
    st.crossings.forEach(cr => {
      total += cr.needed;
      done += Math.min(cr.done, cr.needed);
    }),
  );
  return total > 0 ? { done, total, pct: Math.round((done / total) * 100) } : { done: 0, total: 0, pct: 0 };
}

function formatDate(ts: number): string {
  const d = new Date(ts);
  const now = new Date();
  const diff = now.getTime() - d.getTime();
  const days = Math.floor(diff / 86400000);
  if (days === 0) return "Aujourd'hui";
  if (days === 1) return 'Hier';
  if (days < 7) return `Il y a ${days} jours`;
  return d.toLocaleDateString('fr-FR', { day: '2-digit', month: 'short' });
}

export class WorkflowsView {
  private el: HTMLElement | null = null;
  private detailId: number | null = null;
  private genFilter = 0;
  private search = '';
  private dirty = true;
  private exportMode = false;
  private selectedIds = new Set<number>();

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

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

  update(): void {
    if (!this.dirty) return;
    this.dirty = false;
    this.updateDOM();
  }

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

  private getWorkflows(): WorkflowItem[] {
    return this.queryBus.execute<WorkflowItem[]>({ type: 'get-workflows' });
  }

  private updateDOM(): void {
    if (!this.el) return;
    if (this.detailId !== null) {
      this.renderDetail(this.detailId);
    } else {
      this.renderList();
    }
  }

  // ── List view ──────────────────────────────────────────────────

  private renderList(): void {
    if (!this.el) return;
    const allWorkflows = this.getWorkflows();

    const q = this.search.trim().toLowerCase();
    const filtered = allWorkflows.filter(wf => {
      const gen = RACE_GEN[wf.target] ?? 0;
      const matchGen = this.genFilter === 0 || gen === this.genFilter;
      const matchSearch = !q || wf.target.toLowerCase().includes(q) || wf.name.toLowerCase().includes(q);
      return matchGen && matchSearch;
    });

    let html = '';

    /* Header */
    if (this.exportMode) {
      const allSelected = filtered.length > 0 && filtered.every(wf => this.selectedIds.has(wf.id));
      html += `<div class="wf-export-bar">
        <div class="wf-export-bar-left">
          <button class="wf-io-btn" id="wf-export-cancel">
            <span class="material-symbols-outlined" style="font-size:18px">close</span>
            Annuler
          </button>
          <label class="wf-select-all-label">
            <input type="checkbox" id="wf-select-all" ${allSelected ? 'checked' : ''}>
            <span>Tout sélectionner</span>
          </label>
          <span class="wf-export-count">${this.selectedIds.size} sélectionné${this.selectedIds.size > 1 ? 's' : ''}</span>
        </div>
        <button class="wf-io-btn wf-export-confirm" id="wf-export-confirm"${this.selectedIds.size === 0 ? ' disabled' : ''}>
          <span class="material-symbols-outlined" style="font-size:18px">download</span>
          Exporter (${this.selectedIds.size})
        </button>
      </div>`;
    } else {
      html += `<div class="wf-list-header">
        <div>
          <h2 class="wf-list-title">Sommaire des Plans</h2>
          <p class="wf-list-subtitle">Gérez et suivez l'évolution de vos plans de reproduction.</p>
        </div>
        <div class="wf-header-actions">
          <button class="wf-io-btn" id="wf-import-btn" title="Importer des plans">
            <span class="material-symbols-outlined" style="font-size:18px">upload</span>
            Importer
          </button>
          <button class="wf-io-btn" id="wf-export-btn" title="Exporter les plans"${allWorkflows.length === 0 ? ' disabled' : ''}>
            <span class="material-symbols-outlined" style="font-size:18px">download</span>
            Exporter
          </button>
          <span class="wf-list-count">${allWorkflows.length} plan${allWorkflows.length > 1 ? 's' : ''} actif${allWorkflows.length > 1 ? 's' : ''}</span>
        </div>
      </div>`;
    }

    /* Search + Gen chips */
    html += `<div class="inv-filters-row">
      <div class="inv-search-col">
        <div class="accoup-search-wrap">
          <input class="accoup-search" id="wf-search-input" type="text"
            placeholder="Rechercher un plan…" value="${esc(this.search)}" autocomplete="off">
          ${this.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">
        <div class="accoup-gen-chips" style="margin-bottom:0;border-bottom:none;padding-bottom:0">
          <button class="accoup-gen-chip${this.genFilter === 0 ? ' active' : ''}" data-gen="0">Toutes</button>`;
    for (let g = 1; g <= 10; g++) {
      const hasWf = allWorkflows.some(wf => (RACE_GEN[wf.target] ?? 0) === g);
      if (!hasWf) continue;
      html += `<button class="accoup-gen-chip${this.genFilter === g ? ' active' : ''}" data-gen="${g}">Gen ${g}</button>`;
    }
    html += `</div>
      </div>
    </div>`;

    /* Cards grid */
    if (allWorkflows.length === 0) {
      html += `<div class="wf-empty">
        <span class="material-symbols-outlined" style="font-size:48px;color:var(--md-outline-variant)">assignment</span>
        <p>Aucun plan sauvegardé</p>
        <p style="font-size:12px;color:var(--md-on-surface-variant)">Créez un plan depuis l'onglet Appro ou Inventaire.</p>
      </div>`;
    } else if (filtered.length === 0) {
      html += `<div class="accoup-empty">Aucun plan trouvé</div>`;
    } else {
      html += `<div class="wf-cards-grid">`;
      for (const wf of filtered) {
        html += this.renderWorkflowCard(wf);
      }
      html += `</div>`;
    }

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

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

  private renderWorkflowCard(wf: WorkflowItem): string {
    const prog = getProgress(wf);
    const gen = RACE_GEN[wf.target] ?? 0;
    const genColor = GEN_COLORS[gen] ?? '#888';
    const col = raceColor(wf.target);
    const isSelected = this.selectedIds.has(wf.id);

    return `<div class="wf-card${this.exportMode ? ' wf-card-selectable' : ''}${isSelected ? ' wf-card-selected' : ''}" data-wf-id="${wf.id}">
      ${this.exportMode ? `<div class="wf-card-checkbox"><input type="checkbox" class="wf-card-check" data-wf-id="${wf.id}" ${isSelected ? 'checked' : ''}></div>` : ''}
      <div class="wf-card-top">
        <div class="wf-card-meta">
          <span class="wf-card-gen" style="color:${esc(genColor)}">Génération ${gen}</span>
          <h4 class="wf-card-name">${esc(wf.name)}</h4>
        </div>
        <div class="wf-card-avatar">
          ${getDDImage(wf.target)}
        </div>
      </div>
      <div class="wf-card-progress">
        <div class="wf-card-progress-row">
          <span class="wf-card-progress-label">Progression Actuelle</span>
          <span class="wf-card-progress-pct" style="color:${esc(col)}">${prog.pct}%</span>
        </div>
        <div class="wf-card-bar">
          <div class="wf-card-bar-fill" style="width:${prog.pct}%;background:${esc(col)}"></div>
        </div>
      </div>
      <div class="wf-card-footer">
        <div class="wf-card-date">
          <span class="material-symbols-outlined" style="font-size:14px">history</span>
          Dernière modif : ${formatDate(wf.updatedAt ?? wf.createdAt)}
        </div>
        <div class="wf-card-actions">
          <button class="wf-delete-btn" data-wf-id="${wf.id}" title="Supprimer">
            <span class="material-symbols-outlined" style="font-size:16px">delete</span>
          </button>
          <div class="wf-card-arrow">
            <span class="material-symbols-outlined" style="font-size:18px">arrow_forward</span>
          </div>
        </div>
      </div>
    </div>`;
  }

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

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

    // 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.dirty = true; this.update();
      });
    });

    if (this.exportMode) {
      // Export mode events

      // Cancel export mode
      const cancelBtn = this.el.querySelector('#wf-export-cancel');
      if (cancelBtn) {
        cancelBtn.addEventListener('click', () => {
          this.exportMode = false;
          this.selectedIds.clear();
          this.dirty = true; this.update();
        });
      }

      // Select all
      const selectAll = this.el.querySelector<HTMLInputElement>('#wf-select-all');
      if (selectAll) {
        selectAll.addEventListener('change', () => {
          const allWorkflows = this.getWorkflows();
          // Apply to filtered workflows only
          const q = this.search.trim().toLowerCase();
          const filtered = allWorkflows.filter(wf => {
            const gen = RACE_GEN[wf.target] ?? 0;
            const matchGen = this.genFilter === 0 || gen === this.genFilter;
            const matchSearch = !q || wf.target.toLowerCase().includes(q) || wf.name.toLowerCase().includes(q);
            return matchGen && matchSearch;
          });
          if (selectAll.checked) {
            filtered.forEach(wf => this.selectedIds.add(wf.id));
          } else {
            filtered.forEach(wf => this.selectedIds.delete(wf.id));
          }
          this.dirty = true; this.update();
        });
      }

      // Individual checkboxes (click anywhere on card toggles)
      this.el.querySelectorAll('.wf-card').forEach(card => {
        card.addEventListener('click', (e) => {
          const id = Number((card as HTMLElement).dataset['wfId']);
          if (this.selectedIds.has(id)) {
            this.selectedIds.delete(id);
          } else {
            this.selectedIds.add(id);
          }
          this.dirty = true; this.update();
        });
      });

      // Confirm export
      const confirmBtn = this.el.querySelector('#wf-export-confirm');
      if (confirmBtn) {
        confirmBtn.addEventListener('click', () => this.exportWorkflows());
      }

    } else {
      // Normal mode events

      // Card click → open detail
      this.el.querySelectorAll('.wf-card').forEach(card => {
        card.addEventListener('click', (e) => {
          const target = e.target as HTMLElement;
          if (target.closest('.wf-delete-btn')) return;
          const id = Number((card as HTMLElement).dataset['wfId']);
          this.detailId = id;
          this.dirty = true; this.update();
        });
      });

      // Export button → enter export mode
      const exportBtn = this.el.querySelector('#wf-export-btn');
      if (exportBtn) {
        exportBtn.addEventListener('click', () => {
          this.exportMode = true;
          this.selectedIds.clear();
          this.dirty = true; this.update();
        });
      }

      // Import button
      const importBtn = this.el.querySelector('#wf-import-btn');
      if (importBtn) {
        importBtn.addEventListener('click', () => this.importWorkflows());
      }

      // Delete buttons
      this.el.querySelectorAll('.wf-delete-btn').forEach(btn => {
        btn.addEventListener('click', async (e) => {
          e.stopPropagation();
          const id = Number((btn as HTMLElement).dataset['wfId']);
          const workflows = this.getWorkflows();
          const wf = workflows.find(w => w.id === id);
          const name = wf ? wf.name : String(id);
          const ok = await ConfirmModal.show('Supprimer le plan', `Supprimer "${name}" ? Cette action est irréversible.`);
          if (!ok) return;
          const hasSnap = await UndoManager.snapshotCurrent('Suppression plan');
          this.commandBus.execute({ type: 'delete-workflow', workflowId: id });
          Toast.show('success', `Plan "${name}" supprimé.`, hasSnap ? { label: 'Annuler', callback: () => UndoManager.undo() } : undefined);
          this.dirty = true; this.update();
        });
      });
    }
  }

  // ── Detail view ───────────────────────────────────────────────

  private renderDetail(id: number): void {
    if (!this.el) return;
    const workflows = this.getWorkflows();
    const wf = workflows.find(w => w.id === id);

    if (!wf) {
      this.detailId = null;
      this.dirty = true; this.update();
      return;
    }

    const prog = getProgress(wf);
    const gen = RACE_GEN[wf.target] ?? 0;
    const genColor = GEN_COLORS[gen] ?? '#888';
    const col = raceColor(wf.target);

    let html = '';

    /* Top bar: back + objective + progress */
    html += `<div class="wf-detail-top">
      <button class="reappro-back-btn" id="wf-back-btn">
        <span class="material-symbols-outlined" style="font-size:18px">arrow_back</span>
        Retour au planneur
      </button>
      <div class="wf-detail-objective">
        <span class="material-symbols-outlined" style="font-size:18px;color:var(--md-primary)">timeline</span>
        <span class="wf-detail-obj-text">Objectif : ${esc(wf.target)}</span>
      </div>
      <div class="wf-detail-progress-wrap">
        <div class="wf-detail-progress-info">
          <span class="wf-detail-progress-label">Progression Globale</span>
          <span class="wf-detail-progress-pct" id="wf-global-pct">${prog.pct}%</span>
        </div>
        <div class="wf-detail-progress-bar">
          <div class="wf-detail-progress-fill" id="wf-global-bar" style="width:${prog.pct}%"></div>
        </div>
      </div>
    </div>`;

    /* Overview card */
    html += `<div class="wf-overview-card">
      <div class="wf-overview-left">
        <div class="wf-overview-avatar">
          ${getDDImage(wf.target)}
          <span class="wf-overview-gen-badge" style="background:${esc(genColor)}">GEN ${gen}</span>
        </div>
        <div>
          <h3 class="wf-overview-name">${wf.qty}x ${esc(wf.target)}</h3>
          <p class="wf-overview-meta">Créé le ${new Date(wf.createdAt).toLocaleDateString('fr-FR', { day: '2-digit', month: 'long', year: 'numeric' })}</p>
        </div>
      </div>
      <div class="wf-overview-stats">
        <div class="wf-overview-stat">
          <span class="wf-overview-stat-label">Naissances</span>
          <span class="wf-overview-stat-value" id="wf-stat-births">${prog.done} / ${prog.total}</span>
        </div>
      </div>
    </div>`;

    /* Materials */
    if (wf.materials.length > 0) {
      const totalSteps = wf.steps.length + 1;
      html += `<div class="wf-detail-step-header">
        <span class="wf-detail-step-badge" style="background:var(--md-primary)">Étape 1/${totalSteps}</span>
        <span class="wf-detail-step-label">Géniteurs de Base (Matières Premières)</span>
      </div>`;

      html += `<div class="wf-materials-grid">`;
      wf.materials.forEach((mat, mIdx) => {
        const matDone = Math.min(mat.done, mat.needed);
        const matPct = mat.needed > 0 ? Math.round((matDone / mat.needed) * 100) : 0;
        const matComplete = matDone >= mat.needed;
        html += `<div class="wf-material-card${matComplete ? ' wf-material-complete' : ''}">
          <div class="wf-material-avatar">
            ${getDDImage(mat.name)}
          </div>
          <div class="wf-material-info">
            <div class="wf-material-name-row">
              <p class="wf-material-name">${esc(mat.name)}</p>
              ${matComplete ? '<span class="material-symbols-outlined" style="font-size:16px;color:#22c55e">check_circle</span>' : ''}
            </div>
            <div class="wf-material-progress-row">
              <span class="wf-material-need">Besoin: ${mat.needed}</span>
              <div class="wf-material-bar-wrap">
                <span class="wf-material-count" id="wf-mat-count-${mIdx}">${matDone} / ${mat.needed}</span>
                <div class="wf-material-bar">
                  <div class="wf-material-bar-fill" id="wf-mat-bar-${mIdx}" style="width:${matPct}%"></div>
                </div>
              </div>
            </div>
            <input type="number" class="wf-mat-input" data-mat-idx="${mIdx}" data-max="${mat.needed}" min="0" max="${mat.needed}" value="${matDone}">
          </div>
        </div>`;
      });
      html += `</div>`;

      /* Connector */
      html += `<div class="wf-step-connector"></div>`;
    }

    /* Step cards (crossings by gen) */
    const totalSteps = wf.steps.length + (wf.materials.length > 0 ? 1 : 0);
    wf.steps.forEach((step, sIdx) => {
      const stepNum = sIdx + (wf.materials.length > 0 ? 2 : 1);
      const stepGenColor = GEN_COLORS[step.gen] ?? '#888';

      html += `<div class="wf-detail-step-header">
        <span class="wf-detail-step-badge" style="background:${esc(stepGenColor)}">Étape ${stepNum}/${totalSteps}</span>
        <span class="wf-detail-step-label">Croisements — Génération ${step.gen}</span>
      </div>`;

      html += `<div class="wf-crossings-list">`;
      step.crossings.forEach((cr, cIdx) => {
        const crDone = Math.min(cr.done, cr.needed);
        const crPct = cr.needed > 0 ? Math.round((crDone / cr.needed) * 100) : 0;
        const crCol = raceColor(cr.race);
        const babyGen = RACE_GEN[cr.race] ?? 0;
        const babyGenCol = GEN_COLORS[babyGen] ?? '#888';

        html += `<div class="wf-crossing-card">
          <div class="wf-crossing-row">
            <div class="wf-crossing-parents">
              <div class="wf-crossing-parent-av">
                ${getDDImage(cr.parentA)}
              </div>
              <span class="material-symbols-outlined" style="font-size:16px;color:var(--md-outline-variant)">add</span>
              <div class="wf-crossing-parent-av">
                ${getDDImage(cr.parentB)}
              </div>
            </div>
            <span class="material-symbols-outlined" style="font-size:28px;color:var(--md-primary)">double_arrow</span>
            <div class="wf-crossing-result">
              <div class="wf-crossing-baby-av">
                ${getDDImage(cr.race)}
                <span class="reappro-baby-gen-badge" style="background:${babyGenCol}">G${babyGen}</span>
              </div>
              <div class="wf-crossing-result-info">
                <p class="wf-crossing-baby-name">${esc(cr.race)}</p>
                <p class="wf-crossing-baby-obj">Objectif : ${cr.needed} réussi${cr.needed > 1 ? 's' : ''}</p>
                <div class="wf-crossing-dots">
                  ${Array.from({ length: cr.needed }, (_, i) =>
                    `<span class="wf-dot${i < crDone ? ' wf-dot-done' : ''}" style="${i < crDone ? `background:${esc(crCol)};box-shadow:0 0 8px ${esc(crCol)}60` : ''}"></span>`
                  ).join('')}
                  <span class="wf-crossing-count" id="wf-cr-count-${sIdx}-${cIdx}" style="color:${esc(crCol)}">${crDone} / ${cr.needed}</span>
                </div>
              </div>
            </div>
          </div>
          <input type="number" class="wf-crossing-input" data-step-idx="${sIdx}" data-crossing-idx="${cIdx}" data-max="${cr.needed}" min="0" max="${cr.needed}" value="${crDone}">
        </div>`;
      });
      html += `</div>`;

      /* Connector between steps */
      if (sIdx < wf.steps.length - 1) {
        html += `<div class="wf-step-connector"></div>`;
      }
    });

    this.el.innerHTML = html;
    this.bindDetailEvents(id);
  }

  private bindDetailEvents(wfId: number): void {
    if (!this.el) return;

    // Back button
    const backBtn = this.el.querySelector('#wf-back-btn');
    if (backBtn) {
      backBtn.addEventListener('click', () => {
        this.detailId = null;
        this.dirty = true; this.update();
      });
    }

    // Material inputs
    this.el.querySelectorAll<HTMLInputElement>('.wf-mat-input').forEach(input => {
      let prev = input.value;
      input.addEventListener('focus', () => { prev = input.value; input.value = ''; });
      input.addEventListener('input', () => {
        if (input.value === '') return;
        const mIdx = Number(input.dataset['matIdx']);
        const max = Number(input.dataset['max']) || 0;
        const val = Math.min(Math.max(0, Number(input.value) || 0), max);
        const pct = max > 0 ? Math.round((val / max) * 100) : 0;
        const bar = this.el?.querySelector<HTMLElement>(`#wf-mat-bar-${mIdx}`);
        const cnt = this.el?.querySelector<HTMLElement>(`#wf-mat-count-${mIdx}`);
        if (bar) bar.style.width = `${pct}%`;
        if (cnt) cnt.textContent = `${val} / ${max}`;
        this.refreshGlobalBar();
      });
      input.addEventListener('blur', () => {
        if (input.value === '') { input.value = prev; this.refreshGlobalBar(); return; }
        const mIdx = Number(input.dataset['matIdx']);
        const done = Math.max(0, Number(input.value) || 0);
        this.commandBus.execute({ type: 'update-workflow', workflowId: wfId, materialIdx: mIdx, done });
        this.dirty = true; this.update();
      });
    });

    // Crossing inputs
    this.el.querySelectorAll<HTMLInputElement>('.wf-crossing-input').forEach(input => {
      let prev = input.value;
      input.addEventListener('focus', () => { prev = input.value; input.value = ''; });
      input.addEventListener('input', () => {
        if (input.value === '') return;
        const sIdx = Number(input.dataset['stepIdx']);
        const cIdx = Number(input.dataset['crossingIdx']);
        const max = Number(input.dataset['max']) || 0;
        const val = Math.min(Math.max(0, Number(input.value) || 0), max);
        const cnt = this.el?.querySelector<HTMLElement>(`#wf-cr-count-${sIdx}-${cIdx}`);
        if (cnt) cnt.textContent = `${val} / ${max}`;
        this.refreshGlobalBar();
      });
      input.addEventListener('blur', () => {
        if (input.value === '') { input.value = prev; this.refreshGlobalBar(); return; }
        const sIdx = Number(input.dataset['stepIdx']);
        const cIdx = Number(input.dataset['crossingIdx']);
        const done = Math.max(0, Number(input.value) || 0);
        this.commandBus.execute({ type: 'update-workflow', workflowId: wfId, stepIdx: sIdx, crossingIdx: cIdx, done });
        this.dirty = true; this.update();
      });
    });
  }

  // ── Export / Import ─────────────────────────────────────────

  private async exportWorkflows(): Promise<void> {
    const allWorkflows = this.getWorkflows();
    const toExport = allWorkflows.filter(wf => this.selectedIds.has(wf.id));
    if (toExport.length === 0) return;

    const data = JSON.stringify(toExport, null, 2);
    const suffix = toExport.length === 1 ? toExport[0].target.toLowerCase().replace(/\s+/g, '-') : 'tous';
    const defaultName = `plans-dragodinde-${suffix}-${new Date().toISOString().slice(0, 10)}.json`;

    try {
      const api = (window as any).electronAPI;
      if (api?.exportFile) {
        const ok = await api.exportFile(data, defaultName);
        if (ok) { Toast.show('success', 'Plans exportés avec succès.'); this.exportMode = false; this.selectedIds.clear(); this.dirty = true; this.update(); }
      } else {
        // Fallback navigateur : téléchargement via Blob
        const blob = new Blob([data], { type: 'application/json' });
        const url = URL.createObjectURL(blob);
        const a = document.createElement('a');
        a.href = url;
        a.download = defaultName;
        a.click();
        URL.revokeObjectURL(url);
        Toast.show('success', 'Plans exportés avec succès.');
        this.exportMode = false; this.selectedIds.clear(); this.dirty = true; this.update();
      }
    } catch {
      Toast.show('error', 'Erreur lors de l\'export des plans.');
    }
  }

  private async importWorkflows(): Promise<void> {
    const api = (window as any).electronAPI;
    let raw: string | null = null;

    try {
      if (api?.importFile) {
        raw = await api.importFile();
      } else {
        // Fallback navigateur : input file
        raw = await new Promise<string | null>(resolve => {
          const input = document.createElement('input');
          input.type = 'file';
          input.accept = '.json';
          input.addEventListener('change', () => {
            const file = input.files?.[0];
            if (!file) { resolve(null); return; }
            const reader = new FileReader();
            reader.onload = () => resolve(reader.result as string);
            reader.onerror = () => resolve(null);
            reader.readAsText(file);
          });
          input.click();
        });
      }

      if (!raw) return;

      const parsed = JSON.parse(raw);
      const arr = Array.isArray(parsed) ? parsed : [parsed];

      // Validation basique de la structure
      const valid = arr.filter((item: any) =>
        item && typeof item === 'object' &&
        typeof item.target === 'string' &&
        typeof item.qty === 'number' &&
        Array.isArray(item.materials) &&
        Array.isArray(item.steps),
      ) as WorkflowItem[];

      if (valid.length === 0) {
        Toast.show('error', 'Aucun plan valide trouvé dans le fichier.');
        return;
      }

      this.commandBus.execute({
        type: 'import-workflows',
        workflows: valid,
      } as ImportWorkflowsCommand);

      Toast.show('success', `${valid.length} plan(s) importé(s) avec succès.`);
      this.dirty = true;
      this.update();
    } catch {
      Toast.show('error', 'Erreur lors de l\'import. Vérifiez que le fichier est un JSON valide.');
    }
  }

  private refreshGlobalBar(): void {
    if (!this.el) return;
    let done = 0, total = 0;
    this.el.querySelectorAll<HTMLInputElement>('.wf-mat-input, .wf-crossing-input').forEach(inp => {
      const max = Number(inp.dataset['max']) || 0;
      const val = Math.min(Math.max(0, Number(inp.value) || 0), max);
      total += max;
      done += val;
    });
    const pct = total > 0 ? Math.round((done / total) * 100) : 0;
    const bar = this.el.querySelector<HTMLElement>('#wf-global-bar');
    const pctEl = this.el.querySelector<HTMLElement>('#wf-global-pct');
    const births = this.el.querySelector<HTMLElement>('#wf-stat-births');
    if (bar) bar.style.width = `${pct}%`;
    if (pctEl) pctEl.textContent = `${pct}%`;
    if (births) births.textContent = `${done} / ${total}`;
  }
}
