import { Injectable } from '@angular/core';
import { BehaviorSubject, Observable } from 'rxjs';
import { SnackNotifyConfig, SnackNotifyItem, SnackNotifyType } from './snack-notify.interface';

@Injectable({
  providedIn: 'root'
})
export class SnackNotifyService {
  private notifications$ = new BehaviorSubject<SnackNotifyItem[]>([]);
  private maxNotifications = 5;
  private defaultDuration = 5000; // 5 segundos
  private defaultPosition: 'top-right' = 'top-right';

  constructor() {}

  /**
   * Obtém o observable das notificações ativas
   */
  getNotifications(): Observable<SnackNotifyItem[]> {
    return this.notifications$.asObservable();
  }

  /**
   * Exibe uma notificação
   */
  show(message: string, type: SnackNotifyType = 'info', config?: Partial<SnackNotifyConfig>): string {
    const notificationConfig: SnackNotifyConfig = {
      message,
      type,
      duration: config?.duration ?? this.defaultDuration,
      position: config?.position ?? this.defaultPosition,
      showCloseButton: config?.showCloseButton ?? true,
      icon: config?.icon ?? this.getDefaultIcon(type)
    };

    const notification: SnackNotifyItem = {
      id: this.generateId(),
      config: notificationConfig,
      timestamp: Date.now(),
      isVisible: false // Inicia como false para animação de entrada
    };

    this.addNotification(notification);
    return notification.id;
  }

  /**
   * Métodos de conveniência para diferentes tipos
   */
  success(message: string, config?: Partial<SnackNotifyConfig>): string {
    return this.show(message, 'success', config);
  }

  error(message: string, config?: Partial<SnackNotifyConfig>): string {
    return this.show(message, 'error', config);
  }

  warning(message: string, config?: Partial<SnackNotifyConfig>): string {
    return this.show(message, 'warning', config);
  }

  info(message: string, config?: Partial<SnackNotifyConfig>): string {
    return this.show(message, 'info', config);
  }

  /**
   * Remove uma notificação específica
   */
  dismiss(id: string): void {
    const notifications = this.notifications$.value;
    const notification = notifications.find(n => n.id === id);
    
    if (notification) {
      // Limpar timeout se existir
      if (notification.timeoutId) {
        clearTimeout(notification.timeoutId);
      }
      
      // Marcar como não visível para animação de saída
      notification.isVisible = false;
      this.notifications$.next([...notifications]);
      
      // Remover após animação (300ms)
      setTimeout(() => {
        const updatedNotifications = this.notifications$.value.filter(n => n.id !== id);
        this.notifications$.next(updatedNotifications);
      }, 300);
    }
  }

  /**
   * Remove todas as notificações
   */
  dismissAll(): void {
    const notifications = this.notifications$.value;
    
    // Limpar todos os timeouts
    notifications.forEach(notification => {
      if (notification.timeoutId) {
        clearTimeout(notification.timeoutId);
      }
    });
    
    // Marcar todas como não visíveis
    notifications.forEach(notification => {
      notification.isVisible = false;
    });
    this.notifications$.next([...notifications]);
    
    // Remover todas após animação
    setTimeout(() => {
      this.notifications$.next([]);
    }, 300);
  }

  /**
   * Adiciona uma nova notificação
   */
  private addNotification(notification: SnackNotifyItem): void {
    let notifications = this.notifications$.value;
    
    // Remover notificações antigas se exceder o limite
    if (notifications.length >= this.maxNotifications) {
      const toRemove = notifications.slice(0, notifications.length - this.maxNotifications + 1);
      toRemove.forEach(n => {
        if (n.timeoutId) {
          clearTimeout(n.timeoutId);
        }
      });
      notifications = notifications.slice(notifications.length - this.maxNotifications + 1);
    }
    
    // Adicionar nova notificação
    notifications.push(notification);
    this.notifications$.next(notifications);
    
    // Mostrar com animação após um pequeno delay
    setTimeout(() => {
      notification.isVisible = true;
      this.notifications$.next([...notifications]);
    }, 50);
    
    // Configurar auto-dismiss se duration > 0
    if (notification.config.duration && notification.config.duration > 0) {
      notification.timeoutId = window.setTimeout(() => {
        this.dismiss(notification.id);
      }, notification.config.duration);
    }
  }

  /**
   * Gera um ID único para a notificação
   */
  private generateId(): string {
    return `snack-notify-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;
  }

  /**
   * Obtém o ícone padrão para cada tipo
   */
  private getDefaultIcon(type: SnackNotifyType): string {
    const icons = {
      success: 'fa-check-circle',
      error: 'fa-exclamation-circle',
      warning: 'fa-exclamation-triangle',
      info: 'fa-info-circle'
    };
    return icons[type];
  }
} 