import { Component, OnInit, OnDestroy } from '@angular/core';
import { CommonModule } from '@angular/common';
import { ActivatedRoute, Router, RouterLink } from '@angular/router';
import { FormsModule } from '@angular/forms';
import {
  LucideAngularModule, LucideIconData,
  Dices, ArrowLeft, Square, Trash2, Pencil, Check,
  StickyNote, Sparkles, UserCheck, Plus, X
} from 'lucide-angular';
import { catchError, switchMap, filter, map } from 'rxjs/operators';
import { of } from 'rxjs';
import { SessionService } from '../../services/session.service';
import { Session } from '../../services/session.model';
import { PlaythroughService } from '../../services/playthrough.service';
import {
  SessionEntry, SessionEntryInput, EntryType, ENTRY_TYPE_META
} from '../../services/session-entry.model';
import { SessionEntryService } from '../../services/session-entry.service';
import { LayoutService } from '../../services/layout.service';
import { PageTitleService } from '../../services/page-title.service';
import { ConfirmDialogService } from '../../shared/confirm-dialog/confirm-dialog.service';
import { SessionReferencePanelComponent } from '../session-reference-panel/session-reference-panel.component';
import { DiceRollResult } from '../session-dice-panel/session-dice-panel.component';

/**
 * Vue détail d'une Session avec journal horodaté.
 * Form de saisie en haut, timeline en dessous (plus récent en premier).
 * Le layout dédié "mode jeu" sera ajouté en Phase 4.
 */
@Component({
    selector: 'app-session-detail',
    imports: [CommonModule, FormsModule, LucideAngularModule, RouterLink, SessionReferencePanelComponent],
    templateUrl: './session-detail.component.html',
    styleUrls: ['./session-detail.component.scss']
})
export class SessionDetailComponent implements OnInit, OnDestroy {
  readonly Dices = Dices;
  readonly ArrowLeft = ArrowLeft;
  readonly Square = Square;
  readonly Trash2 = Trash2;
  readonly Pencil = Pencil;
  readonly Check = Check;
  readonly Plus = Plus;
  readonly X = X;

  /** Mapping enum → composant Lucide pour le rendu des icônes par type. */
  readonly typeIcons: Record<EntryType, LucideIconData> = {
    NOTE: StickyNote,
    EVENT: Sparkles,
    DICE_ROLL: Dices,
    PLAYER_ACTION: UserCheck,
  };
  readonly entryTypes: EntryType[] = ['NOTE', 'EVENT', 'DICE_ROLL', 'PLAYER_ACTION'];
  readonly entryTypeMeta = ENTRY_TYPE_META;

  session: Session | null = null;
  /** Résolu via Playthrough.campaignId (Session → Playthrough → Campaign). */
  campaignId: string | null = null;
  /** Timeline triée du plus récent au plus ancien (DESC) pour l'UX en partie. */
  entries: SessionEntry[] = [];

  editingName = false;
  editName = '';

  /** State de la zone "Ajouter une entrée". */
  newEntryType: EntryType = 'NOTE';
  newEntryContent = '';
  submittingEntry = false;

  /** Id de l'entrée en cours d'édition (null si aucune). */
  editingEntryId: string | null = null;
  editEntryType: EntryType = 'NOTE';
  editEntryContent = '';

  constructor(
    private route: ActivatedRoute,
    private router: Router,
    private sessionService: SessionService,
    private playthroughService: PlaythroughService,
    private entryService: SessionEntryService,
    private layoutService: LayoutService,
    private pageTitleService: PageTitleService,
    private confirmDialog: ConfirmDialogService
  ) {}

  ngOnInit(): void {
    this.layoutService.hide();
    this.route.paramMap.pipe(
      map(pm => pm.get('id')),
      filter((id): id is string => !!id),
      switchMap(id => this.sessionService.getSessionById(id).pipe(
        catchError(() => of(null))
      ))
    ).subscribe(session => {
      this.session = session;
      if (session) {
        this.pageTitleService.set(session.name);
        this.loadEntries(session.id);
        if (session.playthroughId) {
          this.playthroughService.getById(session.playthroughId).pipe(
            catchError(() => of(null))
          ).subscribe(pt => { this.campaignId = pt ? pt.campaignId : null; });
        }
      }
    });
  }

  private loadEntries(sessionId: string): void {
    this.entryService.getEntries(sessionId).pipe(
      catchError(() => of([] as SessionEntry[]))
    ).subscribe(list => {
      this.entries = list.slice().sort((a, b) => b.occurredAt.localeCompare(a.occurredAt));
    });
  }

  // ─────────────── Renommage de la Session ───────────────

  startRename(): void {
    if (!this.session) return;
    this.editName = this.session.name;
    this.editingName = true;
  }

  cancelRename(): void {
    this.editingName = false;
    this.editName = '';
  }

  saveRename(): void {
    if (!this.session || !this.editName.trim()) return;
    this.sessionService.renameSession(this.session.id, this.editName.trim()).subscribe({
      next: updated => {
        this.session = updated;
        this.editingName = false;
        this.pageTitleService.set(updated.name);
      },
      error: () => console.error('Erreur lors du renommage de la session')
    });
  }

  // ─────────────── Fin / suppression de Session ───────────────

  endSession(): void {
    if (!this.session || !this.session.active) return;
    const session = this.session;
    this.confirmDialog.confirm({
      title: 'Terminer la session ?',
      message: `Marquer la session "${session.name}" comme terminée ?`,
      details: ['Tu pourras toujours consulter son contenu après.'],
      confirmLabel: 'Terminer',
      variant: 'warning'
    }).then(ok => {
      if (!ok) return;
      this.sessionService.endSession(session.id).subscribe({
        next: updated => this.session = updated,
        error: () => console.error('Erreur lors de la fin de session')
      });
    });
  }

  deleteSession(): void {
    if (!this.session) return;
    const session = this.session;
    const entryCount = this.entries.length;
    const details = [
      entryCount > 0
        ? `${entryCount} entrée${entryCount > 1 ? 's' : ''} de journal sera également supprimée.`
        : 'Aucune entrée de journal pour cette session.',
      'Cette action est irréversible.'
    ];
    this.confirmDialog.confirm({
      title: 'Supprimer la session ?',
      message: `Supprimer définitivement la session "${session.name}" ?`,
      details,
      confirmLabel: 'Supprimer',
      variant: 'danger'
    }).then(ok => {
      if (!ok) return;
      const cid = this.campaignId;
      this.sessionService.deleteSession(session.id).subscribe({
        next: () => {
          if (cid) this.router.navigate(['/campaigns', cid]);
          else this.router.navigate(['/campaigns']);
        },
        error: () => console.error('Erreur lors de la suppression de la session')
      });
    });
  }

  // ─────────────── Ajout d'entrée ───────────────

  submitNewEntry(): void {
    if (!this.session || this.submittingEntry) return;
    const content = this.newEntryContent.trim();
    if (!content) return;
    this.submittingEntry = true;
    const input: SessionEntryInput = { type: this.newEntryType, content };
    this.entryService.createEntry(this.session.id, input).subscribe({
      next: created => {
        this.submittingEntry = false;
        this.entries = [created, ...this.entries];
        this.newEntryContent = '';
      },
      error: () => {
        this.submittingEntry = false;
        console.error('Erreur lors de l\'ajout de l\'entrée');
      }
    });
  }

  // ─────────────── Édition d'entrée ───────────────

  startEditEntry(entry: SessionEntry): void {
    this.editingEntryId = entry.id;
    this.editEntryType = entry.type;
    this.editEntryContent = entry.content;
  }

  cancelEditEntry(): void {
    this.editingEntryId = null;
    this.editEntryContent = '';
  }

  saveEditEntry(entry: SessionEntry): void {
    if (!this.session) return;
    const content = this.editEntryContent.trim();
    if (!content) return;
    const input: SessionEntryInput = { type: this.editEntryType, content };
    this.entryService.updateEntry(this.session.id, entry.id, input).subscribe({
      next: updated => {
        this.entries = this.entries.map(e => e.id === updated.id ? updated : e);
        this.editingEntryId = null;
      },
      error: () => console.error('Erreur lors de la mise à jour de l\'entrée')
    });
  }

  /**
   * Réception d'un jet de dés depuis le panneau latéral.
   * On crée une entrée DICE_ROLL dans le journal avec le résumé formaté.
   */
  onDiceRolled(result: DiceRollResult): void {
    if (!this.session || !this.session.active) return;
    const input: SessionEntryInput = { type: 'DICE_ROLL', content: result.summary };
    this.entryService.createEntry(this.session.id, input).subscribe({
      next: created => this.entries = [created, ...this.entries],
      error: () => console.error('Erreur lors de l\'ajout du jet au journal')
    });
  }

  /**
   * Réception d'une réponse IA à sauvegarder dans le journal.
   * Type NOTE par défaut car c'est le MJ qui choisit de capter une suggestion
   * comme repère — pas un évènement de partie en lui-même.
   */
  onAiReplyToJournal(content: string): void {
    if (!this.session || !this.session.active) return;
    const trimmed = content.trim();
    if (!trimmed) return;
    const input: SessionEntryInput = { type: 'NOTE', content: '💡 ' + trimmed };
    this.entryService.createEntry(this.session.id, input).subscribe({
      next: created => this.entries = [created, ...this.entries],
      error: () => console.error('Erreur lors de l\'ajout de la suggestion IA au journal')
    });
  }

  /**
   * Réception d'un objet de catalogue à consigner dans le journal.
   * Le panneau fournit déjà une chaîne formatée (🛒 …) : on la sauvegarde
   * telle quelle comme entrée NOTE.
   */
  onItemNoteToJournal(content: string): void {
    if (!this.session || !this.session.active) return;
    const trimmed = content.trim();
    if (!trimmed) return;
    const input: SessionEntryInput = { type: 'NOTE', content: trimmed };
    this.entryService.createEntry(this.session.id, input).subscribe({
      next: created => this.entries = [created, ...this.entries],
      error: () => console.error('Erreur lors de l\'ajout de l\'objet au journal')
    });
  }

  deleteEntry(entry: SessionEntry): void {
    if (!this.session) return;
    const session = this.session;
    this.confirmDialog.confirm({
      title: 'Supprimer cette entrée ?',
      message: 'Cette entrée du journal sera définitivement supprimée.',
      confirmLabel: 'Supprimer',
      variant: 'danger'
    }).then(ok => {
      if (!ok) return;
      this.entryService.deleteEntry(session.id, entry.id).subscribe({
        next: () => this.entries = this.entries.filter(e => e.id !== entry.id),
        error: () => console.error('Erreur lors de la suppression de l\'entrée')
      });
    });
  }

  ngOnDestroy(): void {
    this.layoutService.hide();
  }
}
