import { Component, inject, signal } from '@angular/core';
import { AsyncPipe } from '@angular/common';
import { ActivatedRoute, Router } from '@angular/router';
import type { PDFDocumentProxy } from 'pdfjs-dist';
import { PdfService } from './pdf.service';
import { DocumentsService } from '../../core/documents.service';
import { AuthService } from '../../core/auth.service';
import { Annotation, Outil, FORMES } from './annotation.model';
import { PageLayerComponent } from './page-layer.component';
import { SignatureDialogComponent } from './signature-dialog.component';

/**
 * Composant principal de l'éditeur : chargement (drag & drop ou document
 * existant), barre d'outils, navigation/zoom, couches d'édition par page,
 * puis export (téléchargement) et sauvegarde (API).
 */
@Component({
  selector: 'app-editor',
  standalone: true,
  imports: [AsyncPipe, PageLayerComponent, SignatureDialogComponent],
  templateUrl: './editor.component.html',
  styleUrl: './editor.component.scss',
})
export class EditorComponent {
  private readonly pdfService = inject(PdfService);
  private readonly documentsService = inject(DocumentsService);
  private readonly auth = inject(AuthService);
  private readonly route = inject(ActivatedRoute);
  private readonly router = inject(Router);

  /** Binaire du PDF source (conservé pour l'export pdf-lib). */
  private sourcePdf: ArrayBuffer | null = null;
  /** Document pdf.js pour le rendu. */
  readonly pdf = signal<PDFDocumentProxy | null>(null);
  readonly nbPages = signal(0);
  readonly nomDocument = signal('document.pdf');
  /** Identifiant du document si ouvert depuis le dashboard (mode mise à jour). */
  private documentId: string | null = null;

  readonly annotations = signal<Annotation[]>([]);
  readonly outil = signal<Outil>('selection');
  readonly couleur = signal('#000000');
  readonly zoom = signal(1);

  /** Outils « forme » du menu déroulant. */
  readonly formes = FORMES;
  /** Dernière forme choisie (affichée sur le bouton du menu). */
  readonly formeActive = signal<Outil>('rectangle');
  readonly menuFormesOuvert = signal(false);

  /** Charge utile pour les outils image/signature (data URL à poser). */
  readonly chargeUtile = signal<string | null>(null);
  readonly afficheSignature = signal(false);

  readonly chargement = signal(false);
  readonly message = signal<string | null>(null);
  readonly survolDepot = signal(false);

  readonly estConnecte$ = this.auth.estConnecte$;

  /** Pages itérables pour le template. */
  pages = (): number[] =>
    Array.from({ length: this.nbPages() }, (_, i) => i);

  constructor() {
    const id = this.route.snapshot.paramMap.get('id');
    if (id) {
      this.documentId = id;
      this.ouvrirDocumentExistant(id);
    }
  }

  // --- Chargement ---------------------------------------------------------

  private async ouvrirDocumentExistant(id: string): Promise<void> {
    this.chargement.set(true);
    this.documentsService.obtenir(id).subscribe({
      next: (meta) => this.nomDocument.set(meta.name),
      error: () => {},
    });
    this.documentsService.telechargerFichier(id).subscribe({
      next: async (buffer) => {
        await this.chargerBuffer(buffer);
        this.chargement.set(false);
      },
      error: () => {
        this.message.set("Impossible d'ouvrir ce document.");
        this.chargement.set(false);
      },
    });
  }

  async surFichierDepose(ev: DragEvent): Promise<void> {
    ev.preventDefault();
    this.survolDepot.set(false);
    const fichier = ev.dataTransfer?.files?.[0];
    if (fichier) {
      await this.chargerFichier(fichier);
    }
  }

  async surFichierChoisi(ev: Event): Promise<void> {
    const fichier = (ev.target as HTMLInputElement).files?.[0];
    if (fichier) {
      await this.chargerFichier(fichier);
    }
  }

  private async chargerFichier(fichier: File): Promise<void> {
    if (fichier.type !== 'application/pdf') {
      this.message.set('Veuillez déposer un fichier PDF.');
      return;
    }
    this.nomDocument.set(fichier.name);
    this.documentId = null; // nouveau fichier => création à la sauvegarde
    const buffer = await fichier.arrayBuffer();
    await this.chargerBuffer(buffer);
  }

  private async chargerBuffer(buffer: ArrayBuffer): Promise<void> {
    this.message.set(null);
    this.sourcePdf = buffer.slice(0);
    const pdf = await this.pdfService.charger(buffer);
    this.pdf.set(pdf);
    this.nbPages.set(pdf.numPages);
    this.annotations.set([]);
  }

  empecherDefaut(ev: DragEvent): void {
    ev.preventDefault();
    this.survolDepot.set(true);
  }

  finSurvol(ev: DragEvent): void {
    ev.preventDefault();
    this.survolDepot.set(false);
  }

  // --- Barre d'outils -----------------------------------------------------

  choisirOutil(o: Outil): void {
    this.menuFormesOuvert.set(false);
    this.outil.set(o);
    if (o === 'signature') {
      this.afficheSignature.set(true);
    }
  }

  // --- Menu des formes ----------------------------------------------------

  /** Vrai si l'outil donné est une forme (pour l'état actif du bouton menu). */
  estForme(o: Outil): boolean {
    return this.formes.some((f) => f.outil === o);
  }

  /** Icône associée à un outil forme. */
  iconeForme(o: Outil): string {
    return this.formes.find((f) => f.outil === o)?.icone ?? '▭';
  }

  basculerMenuFormes(): void {
    this.menuFormesOuvert.update((v) => !v);
  }

  /** Choix d'une forme dans le menu déroulant. */
  choisirForme(o: Outil): void {
    this.formeActive.set(o);
    this.menuFormesOuvert.set(false);
    this.outil.set(o);
  }

  /** Déclenché par le sélecteur de fichier image caché. */
  async surImageChoisie(ev: Event): Promise<void> {
    const fichier = (ev.target as HTMLInputElement).files?.[0];
    if (!fichier) {
      return;
    }
    const dataUrl = await this.lireDataUrl(fichier);
    this.chargeUtile.set(dataUrl);
    this.outil.set('image');
    this.message.set(
      'Cliquez sur la page pour poser l’image.',
    );
  }

  signatureValidee(dataUrl: string): void {
    this.chargeUtile.set(dataUrl);
    this.outil.set('signature');
    this.afficheSignature.set(false);
    this.message.set('Cliquez sur la page pour poser la signature.');
  }

  signatureAnnulee(): void {
    this.afficheSignature.set(false);
    this.outil.set('selection');
  }

  outilConsomme(): void {
    // Après pose d'un élément ponctuel, on revient en sélection.
    this.outil.set('selection');
    this.chargeUtile.set(null);
    this.message.set(null);
  }

  majAnnotations(liste: Annotation[]): void {
    this.annotations.set(liste);
  }

  // --- Zoom / navigation --------------------------------------------------

  zoomPlus(): void {
    this.zoom.update((z) => Math.min(3, +(z + 0.2).toFixed(2)));
  }

  zoomMoins(): void {
    this.zoom.update((z) => Math.max(0.4, +(z - 0.2).toFixed(2)));
  }

  // --- Export / sauvegarde ------------------------------------------------

  private async genererPdf(): Promise<Uint8Array> {
    if (!this.sourcePdf) {
      throw new Error('Aucun PDF chargé');
    }
    return this.pdfService.exporter(this.sourcePdf, this.annotations());
  }

  async telecharger(): Promise<void> {
    try {
      const octets = await this.genererPdf();
      const blob = new Blob([octets as BlobPart], {
        type: 'application/pdf',
      });
      const url = URL.createObjectURL(blob);
      const a = document.createElement('a');
      a.href = url;
      a.download = this.nomDocument().endsWith('.pdf')
        ? this.nomDocument()
        : `${this.nomDocument()}.pdf`;
      a.click();
      URL.revokeObjectURL(url);
    } catch {
      this.message.set("L'export a échoué.");
    }
  }

  async sauvegarder(): Promise<void> {
    this.chargement.set(true);
    this.message.set(null);
    try {
      const octets = await this.genererPdf();
      const blob = new Blob([octets as BlobPart], {
        type: 'application/pdf',
      });
      const nom = this.nomDocument();
      const requete = this.documentId
        ? this.documentsService.mettreAJour(this.documentId, blob, nom)
        : this.documentsService.creer(blob, nom);
      requete.subscribe({
        next: (doc) => {
          this.documentId = doc.id;
          this.chargement.set(false);
          this.message.set('Document sauvegardé.');
        },
        error: () => {
          this.chargement.set(false);
          this.message.set('La sauvegarde a échoué.');
        },
      });
    } catch {
      this.chargement.set(false);
      this.message.set("Impossible de générer le PDF.");
    }
  }

  allerConnexion(): void {
    this.router.navigate(['/login'], {
      queryParams: { redirige: this.router.url },
    });
  }

  // --- Helpers ------------------------------------------------------------

  private lireDataUrl(fichier: File): Promise<string> {
    return new Promise((resolve, reject) => {
      const reader = new FileReader();
      reader.onload = () => resolve(reader.result as string);
      reader.onerror = reject;
      reader.readAsDataURL(fichier);
    });
  }
}
