import type { CommandBus } from '@application/handlers/CommandBus';
import type { QueryBus } from '@application/handlers/QueryBus';
import type { SettingsResult } from '@application/queries/GetSettings';
import { esc } from '@presentation/helpers/format';
import { Toast } from './Toast';
import { ConfirmModal } from './ConfirmModal';

const NTFY_BASE = 'https://ntfy.mickael-pol.fr';
const NTFY_REDIRECT = 'https://ntfy-redirect.mickael-pol.fr';

const SOUND_OPTIONS: { value: string; label: string; icon: string }[] = [
  { value: 'arpege', label: 'Arpège', icon: 'music_note' },
  { value: 'pulse', label: 'Pulsation', icon: 'pulse_alert' },
  { value: 'fanfare', label: 'Fanfare', icon: 'celebration' },
  { value: 'cloche', label: 'Cloche', icon: 'notifications_active' },
];

export class ParametresView {
  private el: HTMLElement | null = null;
  private modal: HTMLElement | null = null;

  constructor(
    private commandBus: CommandBus,
    private queryBus: QueryBus,
    private playSound?: (name: string) => void,
  ) {}

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

  update(): void {}

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

  private getSettings(): SettingsResult {
    return this.queryBus.execute<SettingsResult>({ type: 'get-settings' });
  }

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

    const { alarmSound, notifsEnabled, ntfyTopic } = this.getSettings();

    let html = '';

    // ── Hero ──────────────────────────────────────────────────────
    html += `<div class="param-hero">
      <div>
        <h2 class="param-hero-title">Param\u00e8tres</h2>
        <p class="param-hero-sub">Configuration de l'application et des notifications.</p>
      </div>
    </div>`;

    // ── Son d'alarme ──────────────────────────────────────────────
    html += `<div class="param-section">
      <div class="param-section-header">
        <span class="material-symbols-outlined param-section-icon">volume_up</span>
        <h3 class="param-section-title">Son d'alarme</h3>
      </div>
      <p class="param-section-desc">Choisissez le son joué lorsqu'un enclos termine sa session.</p>
      <div class="param-sound-grid">`;

    for (const opt of SOUND_OPTIONS) {
      const isActive = alarmSound === opt.value ? ' active' : '';
      html += `<button class="param-sound-card${isActive}" data-sound="${esc(opt.value)}">
        <span class="material-symbols-outlined param-sound-icon">${opt.icon}</span>
        <span class="param-sound-label">${esc(opt.label)}</span>
      </button>`;
    }

    html += `</div>
      <button class="param-test-btn" id="param-test-sound">
        <span class="material-symbols-outlined">play_circle</span>
        Tester le son
      </button>
    </div>`;

    // ── Notifications PC ──────────────────────────────────────────
    html += `<div class="param-section">
      <div class="param-section-header">
        <span class="material-symbols-outlined param-section-icon">notifications</span>
        <h3 class="param-section-title">Notifications PC</h3>
      </div>
      <p class="param-section-desc">Recevez une notification Windows quand un enclos est pr\u00eat.</p>
      <div class="param-toggle-row">
        <span class="param-toggle-label">${notifsEnabled ? 'Notifications activ\u00e9es' : 'Notifications d\u00e9sactiv\u00e9es'}</span>
        <button class="param-toggle${notifsEnabled ? ' active' : ''}" id="param-notifs-toggle">
          <span class="param-toggle-knob"></span>
        </button>
      </div>
    </div>`;

    // ── Notifications Mobile ──────────────────────────────────────
    const mobileActive = ntfyTopic ? ' active' : '';
    html += `<div class="param-section">
      <div class="param-section-header">
        <span class="material-symbols-outlined param-section-icon">phone_android</span>
        <h3 class="param-section-title">Notifications Mobiles</h3>
      </div>
      <p class="param-section-desc">Recevez une alerte sur votre t\u00e9l\u00e9phone via ntfy, m\u00eame loin de votre PC.</p>
      <div class="param-mobile-status">
        <span class="param-mobile-dot${mobileActive}"></span>
        <span class="param-mobile-text">${ntfyTopic ? 'Connect\u00e9 — notifications actives' : 'Non configur\u00e9'}</span>
      </div>
      <button class="param-mobile-btn${mobileActive}" id="param-ntfy-btn">
        <span class="material-symbols-outlined">${ntfyTopic ? 'settings' : 'add_circle'}</span>
        ${ntfyTopic ? 'G\u00e9rer la configuration' : 'Activer les notifications mobiles'}
      </button>
    </div>`;

    // ── Données ──────────────────────────────────────────────────
    html += `<div class="param-section">
      <div class="param-section-header">
        <span class="material-symbols-outlined param-section-icon">database</span>
        <h3 class="param-section-title">Donn\u00e9es</h3>
      </div>
      <p class="param-section-desc">Exportez ou importez toutes vos donn\u00e9es (enclos, dragodindes, statistiques, workflows).</p>
      <div class="param-data-btns">
        <button class="param-data-btn" id="param-export-data">
          <span class="material-symbols-outlined">download</span>
          Exporter les donn\u00e9es
        </button>
        <button class="param-data-btn param-data-btn-import" id="param-import-data">
          <span class="material-symbols-outlined">upload</span>
          Importer les donn\u00e9es
        </button>
      </div>
    </div>`;

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

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

    // Sound cards
    this.el.querySelectorAll<HTMLElement>('.param-sound-card').forEach(card => {
      card.addEventListener('click', () => {
        const sound = card.dataset['sound']!;
        this.commandBus.execute({ type: 'update-settings', alarmSound: sound });
        this.updateDOM();
      });
    });

    // Test sound
    this.el.querySelector('#param-test-sound')?.addEventListener('click', () => {
      const { alarmSound } = this.getSettings();
      this.playSound?.(alarmSound);
    });

    // PC notifications toggle
    this.el.querySelector('#param-notifs-toggle')?.addEventListener('click', () => {
      const { notifsEnabled } = this.getSettings();
      this.commandBus.execute({ type: 'update-settings', notifsEnabled: !notifsEnabled });
      this.updateDOM();
    });

    // Ntfy modal
    this.el.querySelector('#param-ntfy-btn')?.addEventListener('click', () => {
      this.openNtfyModal();
    });

    // Export data
    this.el.querySelector('#param-export-data')?.addEventListener('click', () => this.exportData());

    // Import data
    this.el.querySelector('#param-import-data')?.addEventListener('click', () => this.importData());
  }

  /* ══ Modal ntfy ══ */

  private openNtfyModal(): void {
    if (this.modal) { this.modal.classList.remove('hidden'); this.renderNtfyModal(); return; }

    this.modal = document.createElement('div');
    this.modal.className = 'param-modal-overlay';
    this.modal.innerHTML = `
      <div class="param-modal-box">
        <div class="param-modal-header">
          <div class="param-modal-header-left">
            <span class="material-symbols-outlined" style="color:var(--md-primary)">phone_android</span>
            <h2 class="param-modal-title">Notifications mobiles</h2>
          </div>
          <button class="param-modal-close" id="ntfy-modal-close">
            <span class="material-symbols-outlined">close</span>
          </button>
        </div>
        <div class="param-modal-body" id="ntfy-modal-body"></div>
        <div class="param-modal-footer">
          <button class="param-modal-btn-ghost" id="ntfy-modal-footer-close">Fermer</button>
        </div>
      </div>`;
    document.body.appendChild(this.modal);

    this.modal.querySelector('#ntfy-modal-close')?.addEventListener('click', () => this.closeNtfyModal());
    this.modal.querySelector('#ntfy-modal-footer-close')?.addEventListener('click', () => this.closeNtfyModal());
    this.modal.addEventListener('click', (e) => { if (e.target === this.modal) this.closeNtfyModal(); });

    this.renderNtfyModal();
  }

  private closeNtfyModal(): void {
    this.modal?.classList.add('hidden');
  }

  private renderNtfyModal(): void {
    const body = this.modal?.querySelector('#ntfy-modal-body');
    if (!body) return;

    const { ntfyTopic } = this.getSettings();

    if (!ntfyTopic) {
      body.innerHTML = `
        <div class="param-ntfy-intro">
          <div class="param-ntfy-intro-card">
            <span class="material-symbols-outlined" style="font-size:36px;color:var(--md-primary)">notifications_active</span>
            <p>Recevez une alerte sur votre t\u00e9l\u00e9phone quand un enclos est pr\u00eat, m\u00eame si votre PC est loin !</p>
          </div>
          <button class="param-ntfy-activate" id="ntfy-activate">
            <span class="material-symbols-outlined">add_circle</span>
            Activer les notifications mobiles
          </button>
        </div>`;
      body.querySelector('#ntfy-activate')?.addEventListener('click', () => this.activateNtfy());
      return;
    }

    // QR codes
    const ntfyPlayStore = 'https://play.google.com/store/apps/details?id=io.heckel.ntfy';
    const ntfyAppStore = 'https://apps.apple.com/app/ntfy/id1625396347';
    const qrDownload = `https://api.qrserver.com/v1/create-qr-code/?size=160x160&data=${encodeURIComponent(ntfyPlayStore)}`;
    const redirectUrl = `${NTFY_REDIRECT}/?t=${encodeURIComponent(ntfyTopic)}&s=${encodeURIComponent(NTFY_BASE.replace(/^https?:\/\//, ''))}&n=dd-timer`;
    const qrSubscribe = `https://api.qrserver.com/v1/create-qr-code/?size=180x180&data=${encodeURIComponent(redirectUrl)}`;

    body.innerHTML = `
      <div class="param-ntfy-steps">
        <div class="param-ntfy-step">
          <div class="param-ntfy-step-badge">1</div>
          <div class="param-ntfy-step-content">
            <h4 class="param-ntfy-step-title">Installer l'app ntfy</h4>
            <p class="param-ntfy-step-desc">Scannez ce QR code ou cherchez <strong>ntfy</strong> sur le
              <a href="${ntfyPlayStore}" target="_blank">Play Store</a> /
              <a href="${ntfyAppStore}" target="_blank">App Store</a></p>
            <div class="param-ntfy-qr-wrap">
              <img src="${qrDownload}" width="100" height="100" alt="T\u00e9l\u00e9charger ntfy">
            </div>
          </div>
        </div>

        <div class="param-ntfy-step">
          <div class="param-ntfy-step-badge">2</div>
          <div class="param-ntfy-step-content">
            <h4 class="param-ntfy-step-title">S'abonner aux notifications</h4>
            <p class="param-ntfy-step-desc">Scannez ce QR code avec l'appareil photo de votre t\u00e9l\u00e9phone pour ajouter automatiquement les notifications.</p>
            <div class="param-ntfy-qr-wrap param-ntfy-qr-main">
              <img src="${qrSubscribe}" width="150" height="150" alt="S'abonner aux notifications">
            </div>
          </div>
        </div>
      </div>

      <div class="param-ntfy-actions">
        <button class="param-ntfy-test-btn" id="ntfy-test">
          <span class="material-symbols-outlined">send</span>
          Tester
        </button>
        <button class="param-ntfy-deactivate-btn" id="ntfy-deactivate">
          <span class="material-symbols-outlined">link_off</span>
          D\u00e9sactiver
        </button>
      </div>`;

    body.querySelector('#ntfy-test')?.addEventListener('click', () => this.testNtfy());
    body.querySelector('#ntfy-deactivate')?.addEventListener('click', () => this.deactivateNtfy());
  }

  private activateNtfy(): void {
    const topic = 'dd-' + Math.random().toString(36).slice(2, 8) + '-' + Date.now().toString(36).slice(-4);
    this.commandBus.execute({ type: 'update-settings', ntfyTopic: topic });
    this.updateDOM();
    this.renderNtfyModal();
  }

  private deactivateNtfy(): void {
    this.commandBus.execute({ type: 'update-settings', ntfyTopic: '' });
    this.updateDOM();
    this.renderNtfyModal();
  }

  private testNtfy(): void {
    const { ntfyTopic } = this.getSettings();
    if (!ntfyTopic) return;
    const url = `${NTFY_BASE}/${ntfyTopic}`;
    (window as any).electronAPI?.sendNtfy?.(url, 'Test alarme', 'Ceci est un test de la notification mobile Obsidienne !');
  }

  /* ══ Backup / Restore ══ */

  private async exportData(): Promise<void> {
    const api = (window as any).electronAPI;
    if (!api?.loadData || !api?.exportFile) return;

    try {
      const raw = await api.loadData();
      if (!raw) {
        Toast.show('error', 'Aucune donnée à exporter.');
        return;
      }

      const version = await api.getVersion?.() ?? 'unknown';
      const backup = {
        app: 'obsidienne',
        version,
        exportedAt: new Date().toISOString(),
        data: JSON.parse(raw),
      };

      const date = new Date().toISOString().slice(0, 10);
      const ok = await api.exportFile(JSON.stringify(backup, null, 2), `dd-timer-backup-${date}.json`);
      if (ok) {
        Toast.show('success', 'Données exportées avec succès.');
      }
    } catch {
      Toast.show('error', 'Erreur lors de l\'export des données.');
    }
  }

  private async importData(): Promise<void> {
    const api = (window as any).electronAPI;
    if (!api?.importFile || !api?.saveData) return;

    try {
      const raw = await api.importFile();
      if (!raw) return; // dialogue annulé

      let parsed: any;
      try {
        parsed = JSON.parse(raw);
      } catch {
        Toast.show('error', 'Le fichier sélectionné n\'est pas un JSON valide.');
        return;
      }

      // Validation structurelle des données importées
      const validateEnclosData = (data: any): boolean => {
        if (!data || typeof data !== 'object' || data === null) return false;
        if (!Array.isArray(data.enclos)) return false;
        return data.enclos.every((enc: any) =>
          enc && typeof enc === 'object' &&
          typeof enc.id === 'number' &&
          typeof enc.name === 'string' &&
          Array.isArray(enc.dragodindes) &&
          enc.gaugeLevels && typeof enc.gaugeLevels === 'object' &&
          enc.timer && typeof enc.timer === 'object',
        );
      };

      // Validation du format backup
      if ((parsed.app === 'obsidienne' || parsed.app === 'minuteur-dragodinde') && parsed.data && typeof parsed.data === 'object' && parsed.data !== null) {
        if (!validateEnclosData(parsed.data)) {
          Toast.show('error', 'Le backup contient des données corrompues ou incomplètes.');
          return;
        }
        const date = parsed.exportedAt ? new Date(parsed.exportedAt).toLocaleDateString('fr-FR') : 'inconnue';
        const ok = await ConfirmModal.show(
          'Importer les données',
          `Ce backup date du ${date} (v${parsed.version ?? '?'}). Toutes vos données actuelles seront remplacées. Continuer ?`,
        );
        if (!ok) return;
        api.saveData(JSON.stringify(parsed.data));
      } else if (parsed.enclos && Array.isArray(parsed.enclos)) {
        if (!validateEnclosData(parsed)) {
          Toast.show('error', 'Le fichier contient des données corrompues ou incomplètes.');
          return;
        }
        const ok = await ConfirmModal.show(
          'Importer les données',
          'Toutes vos données actuelles seront remplacées. Continuer ?',
        );
        if (!ok) return;
        api.saveData(JSON.stringify(parsed));
      } else {
        Toast.show('error', 'Format de fichier non reconnu.');
        return;
      }

      Toast.show('success', 'Données importées. Rechargement...');
      setTimeout(() => window.location.reload(), 1000);
    } catch {
      Toast.show('error', 'Erreur lors de l\'import des données.');
    }
  }
}
