import type { CommandBus } from '@application/handlers/CommandBus';
import type { QueryBus } from '@application/handlers/QueryBus';
import type { UIState } from '@presentation/state/UIState';
import type { DashboardResult } from '@application/queries/GetDashboard';
import { Sidebar } from './Sidebar';
import { Dashboard } from './Dashboard';
import { EnclosView } from './EnclosView';
import { AccouplementView } from './AccouplementView';
import { ReapproView } from './ReapproView';
import { InventaireView } from './InventaireView';
import { ParametresView } from './ParametresView';
import { WorkflowsView } from './WorkflowsView';
import { StatistiquesView } from './StatistiquesView';
import { UpdateBanner } from './UpdateBanner';
import { Toast } from './Toast';
import { ConfirmModal } from './ConfirmModal';
import { UndoManager } from '@presentation/services/UndoManager';
import { esc } from '@presentation/helpers/format';
import { enclosGlobalState } from '@presentation/helpers/gauge-live';
import { MAX_ENCLOS } from '@domain/entities/Enclos';
import type { Enclos } from '@domain/entities/Enclos';

type ChildComponent = { update(): void; destroy(): void };

export class App {
  private root: HTMLElement;
  private sidebar: Sidebar;
  private updateBanner: UpdateBanner;
  private activeChild: ChildComponent | null = null;
  private unsubscribe: (() => void) | null = null;
  private rafId: number | null = null;
  private completionIntervalId: number | null = null;
  private ctrlZHandler: ((e: KeyboardEvent) => void) | null = null;
  private lastView: string | number | null = null;

  // Tab drag-and-drop state
  private dragSrcIdx: number | null = null;

  constructor(
    private commandBus: CommandBus,
    private queryBus: QueryBus,
    private uiState: UIState,
    rootElement: HTMLElement,
    private playSound?: (name: string) => void,
  ) {
    this.root = rootElement;
    this.sidebar = new Sidebar(uiState, queryBus);
    this.updateBanner = new UpdateBanner();
  }

  render(): void {
    this.root.innerHTML = `
      <div class="app-shell">
        <div id="sb-container"></div>
        <div class="main-area">
          <header class="app-header">
            <button class="app-hamburger" id="hamburger-btn">&#9776;</button>
            <div class="app-header-text">
              <h1 class="app-title"><span class="app-title-icon">&#x2694;</span> Obsidienne</h1>
              <p class="app-subtitle">Dofus 3 &middot; Gestion multi-enclos en temps r&eacute;el</p>
            </div>
            <div class="app-hamburger" style="visibility:hidden;pointer-events:none;" aria-hidden="true"></div>
          </header>
          <div id="update-banner-root"></div>
          <div class="tabs-row" id="tabs-row"></div>
          <div id="enclos-content" class="main-content custom-scrollbar"></div>
        </div>
      </div>
    `;

    // Mount sidebar
    const sbContainer = this.root.querySelector('#sb-container') as HTMLElement;
    this.sidebar.render(sbContainer);

    // Mount update banner
    const bannerRoot = this.root.querySelector('#update-banner-root') as HTMLElement;
    this.updateBanner.render(bannerRoot);

    // Mount toast container
    const appShell = this.root.querySelector('.app-shell') as HTMLElement;
    Toast.mount(appShell);

    // Ctrl+Z → undo
    this.ctrlZHandler = (e: KeyboardEvent) => {
      if ((e.ctrlKey || e.metaKey) && e.key === 'z' && UndoManager.canUndo()) {
        e.preventDefault();
        UndoManager.undo();
      }
    };
    document.addEventListener('keydown', this.ctrlZHandler);

    // DEV badge via IPC (pas d'executeJavaScript)
    const api = (window as any).electronAPI;
    api?.onDevMode?.(() => {
      const p = this.root.querySelector('header p');
      if (p && !document.getElementById('dev-badge')) {
        const b = document.createElement('span');
        b.id = 'dev-badge';
        b.textContent = 'DEV';
        b.style.cssText = 'background:#ff9820;color:#000;padding:2px 10px;border-radius:8px;font-size:0.72rem;font-weight:800;margin-left:8px;vertical-align:middle';
        p.appendChild(b);
      }
    });

    // Hamburger toggle
    const hamburgerBtn = this.root.querySelector('#hamburger-btn') as HTMLElement;
    hamburgerBtn.addEventListener('click', () => this.uiState.toggleSidebar());

    // Subscribe to UI state changes
    this.unsubscribe = this.uiState.subscribe(() => this.onStateChange());

    // Initial renders
    this.renderTabs();
    this.renderContent();
    this.updateSidebarState();

    // Start animation loop
    this.startAnimationLoop();

    // Interval indépendant du focus fenêtre pour la détection de fin de session
    this.completionIntervalId = window.setInterval(() => {
      this.checkAllEnclosCompletion();
    }, 1000);
  }

  private onStateChange(): void {
    this.renderTabs();
    this.renderContent();
    this.sidebar.update();
    this.updateSidebarState();
  }

  private updateSidebarState(): void {
    const sidebarEl = this.root.querySelector('.sidebar-new') as HTMLElement | null;
    if (sidebarEl) {
      sidebarEl.classList.toggle('sidebar-closed', !this.uiState.sidebarOpen);
    }
  }

  private getDashboardData(): DashboardResult {
    return this.queryBus.execute<DashboardResult>({ type: 'get-dashboard' });
  }

  // ── Tabs ──────────────────────────────────────────────────────
  private renderTabs(): void {
    const tabsRow = this.root.querySelector('#tabs-row') as HTMLElement | null;
    if (!tabsRow) return;

    const data = this.getDashboardData();
    const enclosList = data.enclosSummaries;
    const activeView = this.uiState.activeView;

    let html = '';

    // Dashboard tab
    const dashActive = activeView === 'dashboard' ? ' active' : '';
    html += `<div class="tab${dashActive}" data-view="dashboard"><span><span class="sb-item-icon material-symbols-outlined" style="font-size:15px;vertical-align:middle;margin-right:4px;">dashboard</span>Dashboard</span></div>`;

    // Statistiques tab
    const statsActive = activeView === 'statistiques' ? ' active' : '';
    html += `<div class="tab${statsActive}" data-view="statistiques"><span><span class="sb-item-icon material-symbols-outlined" style="font-size:15px;vertical-align:middle;margin-right:4px;">bar_chart</span>Statistiques</span></div>`;

    // Enclos tabs
    enclosList.forEach((enc, idx) => {
      const isActive = activeView === enc.id ? ' active' : '';
      const isRunning = enc.running ? ' running' : '';
      const canDelete = enclosList.length > 1;
      html += `<div class="tab${isActive}${isRunning}" draggable="true" data-idx="${idx}" data-view="${enc.id}" id="tab-enc-${enc.id}">`;
      html += `<span class="tab-dot"></span>`;
      html += `<span>${esc(enc.name)}</span>`;
      if (canDelete) {
        html += `<button class="tab-del" data-delete-id="${enc.id}" title="Supprimer">&#x2715;</button>`;
      }
      html += `</div>`;
    });

    // Add enclos button
    const disabled = enclosList.length >= MAX_ENCLOS ? ' disabled' : '';
    html += `<button class="add-tab" id="add-enclos-btn"${disabled}>+ Enclos</button>`;

    tabsRow.innerHTML = html;

    // Tab click events
    tabsRow.querySelectorAll('.tab[data-view]').forEach(tab => {
      tab.addEventListener('click', (e) => {
        const target = e.target as HTMLElement;
        if (target.classList.contains('tab-del')) return;
        const view = (tab as HTMLElement).dataset['view']!;
        const viewValue = /^\d+$/.test(view) ? Number(view) : view;
        this.uiState.setActiveView(viewValue);
      });
    });

    // Delete events
    tabsRow.querySelectorAll('.tab-del').forEach(btn => {
      btn.addEventListener('click', async (e) => {
        e.stopPropagation();
        const id = Number((btn as HTMLElement).dataset['deleteId']);
        const ok = await ConfirmModal.show('Supprimer l\'enclos', 'Cette action est irréversible. Continuer ?');
        if (!ok) return;
        const hasSnap = await UndoManager.snapshotCurrent('Suppression enclos');
        this.commandBus.execute({ type: 'delete-enclos', enclosId: id });
        Toast.show('success', 'Enclos supprimé.', hasSnap ? { label: 'Annuler', callback: () => UndoManager.undo() } : undefined);
        if (this.uiState.activeView === id) {
          const newData = this.getDashboardData();
          const firstEnclos = newData.enclosSummaries[0];
          this.uiState.setActiveView(firstEnclos ? firstEnclos.id : 'dashboard');
        } else {
          this.uiState.notify();
        }
      });
    });

    // Add enclos button
    const addBtn = tabsRow.querySelector('#add-enclos-btn') as HTMLElement | null;
    if (addBtn) {
      addBtn.addEventListener('click', () => {
        this.commandBus.execute({ type: 'create-enclos' });
        const newData = this.getDashboardData();
        const last = newData.enclosSummaries[newData.enclosSummaries.length - 1];
        if (last) this.uiState.setActiveView(last.id);
      });
    }

    // Drag and drop
    this.setupTabDragAndDrop(tabsRow);
  }

  private setupTabDragAndDrop(tabsRow: HTMLElement): void {
    const tabs = tabsRow.querySelectorAll('.tab[draggable=true]') as NodeListOf<HTMLElement>;

    tabs.forEach(tab => {
      tab.addEventListener('dragstart', (e) => {
        this.dragSrcIdx = Number(tab.dataset['idx']);
        (e as DragEvent).dataTransfer!.effectAllowed = 'move';
        tab.classList.add('dragging');
      });

      tab.addEventListener('dragover', (e) => {
        e.preventDefault();
        (e as DragEvent).dataTransfer!.dropEffect = 'move';
        tab.classList.add('drag-over');
      });

      tab.addEventListener('dragleave', () => {
        tab.classList.remove('drag-over');
      });

      tab.addEventListener('dragend', () => {
        tab.classList.remove('dragging');
        tabs.forEach(t => t.classList.remove('drag-over'));
      });

      tab.addEventListener('drop', (e) => {
        e.preventDefault();
        tab.classList.remove('drag-over');
        const destIdx = Number(tab.dataset['idx']);
        if (this.dragSrcIdx !== null && this.dragSrcIdx !== destIdx) {
          this.commandBus.execute({
            type: 'reorder-enclos',
            fromIndex: this.dragSrcIdx,
            toIndex: destIdx,
          });
          this.uiState.notify();
        }
        this.dragSrcIdx = null;
      });
    });
  }

  // ── Content routing ───────────────────────────────────────────
  private renderContent(): void {
    const view = this.uiState.activeView;

    if (view === this.lastView && this.activeChild) {
      this.activeChild.update();
      return;
    }

    if (this.activeChild) {
      this.activeChild.destroy();
      this.activeChild = null;
    }

    const container = this.root.querySelector('#enclos-content') as HTMLElement | null;
    if (!container) return;
    container.innerHTML = '';

    this.lastView = view;

    if (view === 'dashboard') {
      const child = new Dashboard(this.commandBus, this.queryBus, this.uiState);
      child.render(container);
      this.activeChild = child;
    } else if (view === 'accouplement') {
      const child = new AccouplementView(this.commandBus, this.queryBus);
      child.render(container);
      this.activeChild = child;
    } else if (view === 'appro') {
      const child = new ReapproView(this.commandBus, this.queryBus);
      child.render(container);
      this.activeChild = child;
    } else if (view === 'inventaire') {
      const child = new InventaireView(this.commandBus, this.queryBus);
      child.render(container);
      this.activeChild = child;
    } else if (view === 'workflows') {
      const child = new WorkflowsView(this.commandBus, this.queryBus, this.uiState);
      child.render(container);
      this.activeChild = child;
    } else if (view === 'statistiques') {
      const child = new StatistiquesView(this.commandBus, this.queryBus);
      child.render(container);
      this.activeChild = child;
    } else if (view === 'parametres') {
      const child = new ParametresView(this.commandBus, this.queryBus, this.playSound);
      child.render(container);
      this.activeChild = child;
    } else if (typeof view === 'number') {
      const child = new EnclosView(this.commandBus, this.queryBus, this.uiState);
      child.render(container, view);
      this.activeChild = child;
    }
  }

  // ── Live update loop ──────────────────────────────────────────
  private startAnimationLoop(): void {
    const loop = () => {
      this.updateTabDots();
      if (this.activeChild) this.activeChild.update();
      this.rafId = requestAnimationFrame(loop);
    };
    this.rafId = requestAnimationFrame(loop);
  }

  private updateTabDots(): void {
    const data = this.getDashboardData();
    data.enclosSummaries.forEach(enc => {
      const tab = this.root.querySelector(`#tab-enc-${enc.id}`) as HTMLElement | null;
      if (!tab) return;
      tab.classList.toggle('running', enc.running);
    });
  }

  /** Appelle complete-timer sur tout enclos dont toutes les cibles sont atteintes. */
  private checkAllEnclosCompletion(): void {
    const data = this.getDashboardData();
    data.enclosSummaries.forEach(summary => {
      if (!summary.running) return;
      const enc = this.queryBus.execute<Enclos>({ type: 'get-enclos-detail', enclosId: summary.id });
      if (!enc.dragodindes.length || !enc.activeGauges.length) return;
      const { allDone } = enclosGlobalState(enc);
      if (allDone) {
        this.commandBus.execute({ type: 'complete-timer', enclosId: summary.id });
      }
    });
  }

  destroy(): void {
    if (this.rafId !== null) {
      cancelAnimationFrame(this.rafId);
      this.rafId = null;
    }
    if (this.completionIntervalId !== null) {
      clearInterval(this.completionIntervalId);
      this.completionIntervalId = null;
    }
    if (this.ctrlZHandler) {
      document.removeEventListener('keydown', this.ctrlZHandler);
      this.ctrlZHandler = null;
    }
    if (this.unsubscribe) {
      this.unsubscribe();
      this.unsubscribe = null;
    }
    if (this.activeChild) {
      this.activeChild.destroy();
      this.activeChild = null;
    }
    this.sidebar.destroy();
    this.updateBanner.destroy();
    this.root.innerHTML = '';
  }
}
