import { ToastNotification } from '../components/NotificationToast'

type NotificationCallback = (notifications: ToastNotification[]) => void

// Centralized icon constants for consistency
export const ICONS = {
  // Status
  SUCCESS: '✅',
  ERROR: '❌',
  WARNING: '⚠️',
  INFO: '📋',
  PROCESSING: '⏳',

  // Actions
  DELETE: '🗑️',
  SAVE: '💾',
  SYNC: '🔄',
  DOWNLOAD: '📥',
  COPY: '📋',

  // Features
  REVIEW: '👁️',
  FACE: '👤',
  SCHEDULER: '📅',

  // Platforms
  INSTAGRAM: '📸',
  TIKTOK: '🎵',
  SNAPCHAT: '👻',
  FORUM: '💬',
  YOUTUBE: '▶️',
  PLEX: '🎬',
} as const

/**
 * Extract error message from various error types consistently
 */
export function extractErrorMessage(err: unknown, fallback: string = 'An error occurred'): string {
  if (!err) return fallback

  // Axios-style error with response.data.detail
  if (typeof err === 'object' && err !== null) {
    const e = err as Record<string, unknown>

    // Check for axios response structure
    if (e.response && typeof e.response === 'object') {
      const response = e.response as Record<string, unknown>
      if (response.data && typeof response.data === 'object') {
        const data = response.data as Record<string, unknown>
        if (typeof data.detail === 'string') return data.detail
        if (typeof data.message === 'string') return data.message
        if (typeof data.error === 'string') return data.error
      }
    }

    // Standard Error object
    if (e.message && typeof e.message === 'string') return e.message

    // Plain object with error/detail/message
    if (typeof e.detail === 'string') return e.detail
    if (typeof e.error === 'string') return e.error
  }

  // String error
  if (typeof err === 'string') return err

  return fallback
}

class NotificationManager {
  private notifications: ToastNotification[] = []
  private listeners: Set<NotificationCallback> = new Set()
  private idCounter = 0

  subscribe(callback: NotificationCallback) {
    this.listeners.add(callback)
    // Immediately notify with current state
    callback(this.notifications)

    return () => {
      this.listeners.delete(callback)
    }
  }

  private notify() {
    this.listeners.forEach(callback => callback([...this.notifications]))
  }

  show(title: string, message: string, icon?: string, type?: 'success' | 'error' | 'info' | 'warning', thumbnailUrl?: string) {
    const notification: ToastNotification = {
      id: `notification-${++this.idCounter}-${Date.now()}`,
      title,
      message,
      icon,
      type,
      thumbnailUrl
    }

    this.notifications.push(notification)
    this.notify()

    return notification.id
  }

  dismiss(id: string) {
    this.notifications = this.notifications.filter(n => n.id !== id)
    this.notify()
  }

  // ============================================
  // Core convenience methods
  // ============================================

  success(title: string, message: string, icon: string = ICONS.SUCCESS, thumbnailUrl?: string) {
    return this.show(title, message, icon, 'success', thumbnailUrl)
  }

  error(title: string, message: string, icon: string = ICONS.ERROR, thumbnailUrl?: string) {
    return this.show(title, message, icon, 'error', thumbnailUrl)
  }

  info(title: string, message: string, icon: string = ICONS.INFO, thumbnailUrl?: string) {
    return this.show(title, message, icon, 'info', thumbnailUrl)
  }

  warning(title: string, message: string, icon: string = ICONS.WARNING, thumbnailUrl?: string) {
    return this.show(title, message, icon, 'warning', thumbnailUrl)
  }

  // ============================================
  // Settings & Configuration
  // ============================================

  /** Notify that settings were saved successfully */
  settingsSaved(category: string) {
    return this.success('Settings Saved', `${category} settings saved successfully`)
  }

  /** Notify that saving settings failed */
  settingsSaveError(err: unknown, category?: string) {
    const what = category ? `${category} settings` : 'settings'
    return this.error('Save Failed', extractErrorMessage(err, `Failed to save ${what}`))
  }

  // ============================================
  // Connection & Authentication
  // ============================================

  /** Notify successful connection */
  connectionSuccess(service: string, message?: string) {
    return this.success('Connected', message || `Connected to ${service}`)
  }

  /** Notify connection failure */
  connectionFailed(service: string, err?: unknown) {
    return this.error('Connection Failed', extractErrorMessage(err, `Could not connect to ${service}`))
  }

  /** Notify disconnection */
  disconnected(service: string) {
    return this.success('Disconnected', `${service} has been disconnected`)
  }

  // ============================================
  // CRUD Operations
  // ============================================

  /** Notify successful deletion */
  deleted(itemType: string, message?: string) {
    return this.success(`${itemType} Deleted`, message || `${itemType} removed successfully`, ICONS.DELETE)
  }

  /** Notify deletion failure */
  deleteError(itemType: string, err?: unknown) {
    return this.error('Delete Failed', extractErrorMessage(err, `Failed to delete ${itemType.toLowerCase()}`))
  }

  /** Notify successful move/keep operation */
  moved(itemType: string, destination?: string, count?: number) {
    const countStr = count !== undefined ? `${count} ` : ''
    const destStr = destination ? ` to ${destination}` : ''
    return this.success(`${itemType} Moved`, `${countStr}${itemType.toLowerCase()}${count !== 1 ? 's' : ''} moved${destStr}`)
  }

  /** Notify move failure */
  moveError(itemType: string, err?: unknown) {
    return this.error('Move Failed', extractErrorMessage(err, `Failed to move ${itemType.toLowerCase()}`))
  }

  /** Notify item kept (moved from review to destination) */
  kept(itemType: string = 'Image') {
    return this.success(`${itemType} Kept`, `${itemType} moved to destination`)
  }

  // ============================================
  // Batch Operations
  // ============================================

  /** Notify successful batch operation */
  batchSuccess(operation: string, count: number, itemType: string = 'item') {
    const plural = count !== 1 ? 's' : ''
    return this.success(`Batch ${operation}`, `${count} ${itemType}${plural} ${operation.toLowerCase()}`)
  }

  /** Notify batch operation failure */
  batchError(operation: string, err?: unknown) {
    return this.error(`Batch ${operation}`, extractErrorMessage(err, `${operation} operation failed`))
  }

  // ============================================
  // Face Recognition
  // ============================================

  /** Notify face reference added */
  faceReferenceAdded(personName: string, filename?: string) {
    return this.success('Face Reference Added', filename || `Added as reference for ${personName}`, ICONS.FACE)
  }

  /** Notify face reference operation failed */
  faceReferenceError(err: unknown) {
    return this.error('Add Reference Failed', extractErrorMessage(err, 'Failed to add face reference'))
  }

  /** Notify processing started (for async operations) */
  processing(message: string) {
    return this.info('Processing', message, ICONS.PROCESSING)
  }

  /** Notify item moved to review queue */
  movedToReview(count: number = 1) {
    const plural = count !== 1 ? 's' : ''
    return this.success('Moved to Review', `${count} item${plural} moved to review queue`, ICONS.REVIEW)
  }

  // ============================================
  // Sync & Background Operations
  // ============================================

  /** Notify sync started */
  syncStarted(what: string) {
    return this.success('Sync Started', `${what} sync started in background`, ICONS.SYNC)
  }

  /** Notify sync completed */
  syncCompleted(what: string) {
    return this.success('Sync Complete', `${what} sync completed`, ICONS.SYNC)
  }

  /** Notify sync failed */
  syncError(what: string, err?: unknown) {
    return this.error('Sync Failed', extractErrorMessage(err, `Failed to sync ${what.toLowerCase()}`))
  }

  /** Notify rescan started */
  rescanStarted(count?: number) {
    const msg = count ? `Scanning ${count} files...` : 'Rescan started'
    return this.info('Rescan Started', msg, ICONS.SYNC)
  }

  /** Notify rescan completed */
  rescanCompleted(count: number, matched?: number) {
    const matchedStr = matched !== undefined ? `, ${matched} matched` : ''
    return this.success('Rescan Complete', `Processed ${count} files${matchedStr}`, ICONS.SYNC)
  }

  // ============================================
  // Scheduler Operations
  // ============================================

  /** Notify scheduler started */
  schedulerStarted() {
    return this.success('Scheduler Started', 'The scheduler service has been started successfully', ICONS.SCHEDULER)
  }

  /** Notify scheduler stopped */
  schedulerStopped() {
    return this.success('Scheduler Stopped', 'The scheduler service has been stopped', ICONS.SCHEDULER)
  }

  /** Notify scheduler operation failed */
  schedulerError(operation: string, err?: unknown) {
    return this.error(`${operation} Failed`, extractErrorMessage(err, `Failed to ${operation.toLowerCase()} scheduler`))
  }

  /** Notify download stopped */
  downloadStopped(platform: string) {
    const platformName = this.formatPlatformName(platform)
    return this.success('Download Stopped', `${platformName} download has been stopped`)
  }

  // ============================================
  // Clipboard Operations
  // ============================================

  /** Notify content copied to clipboard */
  copied(what: string = 'Content') {
    return this.success('Copied', `${what} copied to clipboard`, ICONS.COPY)
  }

  // ============================================
  // Validation
  // ============================================

  /** Notify validation error */
  validationError(message: string) {
    return this.error('Required', message)
  }

  // ============================================
  // Date/Time Operations
  // ============================================

  /** Notify date updated */
  dateUpdated(itemType: string = 'File') {
    return this.success('Date Updated', `${itemType} date updated successfully`)
  }

  /** Notify date update failed */
  dateUpdateError(err?: unknown) {
    return this.error('Date Update Failed', extractErrorMessage(err, 'Failed to update file date'))
  }

  // ============================================
  // Download Operations
  // ============================================

  /** Notify ZIP download ready */
  downloadReady(count: number) {
    return this.success('Download Ready', `ZIP file with ${count} items is ready`, ICONS.DOWNLOAD)
  }

  // ============================================
  // Platform-specific notifications
  // ============================================

  downloadStarted(platform: string, username: string, thumbnailUrl?: string) {
    const icons: Record<string, string> = {
      instagram: ICONS.INSTAGRAM,
      fastdl: ICONS.INSTAGRAM,
      imginn: ICONS.INSTAGRAM,
      toolzu: ICONS.INSTAGRAM,
      tiktok: ICONS.TIKTOK,
      snapchat: ICONS.SNAPCHAT,
      forum: ICONS.FORUM,
    }
    const icon = icons[platform.toLowerCase()] || ICONS.DOWNLOAD
    const platformName = this.formatPlatformName(platform)

    return this.info(`${platformName}`, `Downloading from ${username}...`, icon, thumbnailUrl)
  }

  downloadCompleted(platform: string, filename: string, username?: string, thumbnailUrl?: string) {
    const icons: Record<string, string> = {
      instagram: ICONS.INSTAGRAM,
      fastdl: ICONS.INSTAGRAM,
      imginn: ICONS.INSTAGRAM,
      toolzu: ICONS.INSTAGRAM,
      tiktok: ICONS.TIKTOK,
      snapchat: ICONS.SNAPCHAT,
      forum: ICONS.FORUM,
    }
    const icon = icons[platform.toLowerCase()] || ICONS.DOWNLOAD
    const platformName = this.formatPlatformName(platform)
    // Don't show " from all" when username is "all" (platform-wide download)
    const from = username && username !== 'all' ? ` from ${username}` : ''

    return this.success(`${platformName} Download Complete`, `${filename}${from}`, icon, thumbnailUrl)
  }

  downloadError(platform: string, error: string) {
    const platformName = this.formatPlatformName(platform)
    return this.error(`${platformName} Error`, error, ICONS.WARNING)
  }

  reviewQueue(_platform: string, count: number, username?: string) {
    const from = username ? ` from ${username}` : ''
    const itemText = count === 1 ? 'item' : 'items'
    return this.show(
      `Review Queue${from ? `: ${username}` : ''}`,
      `${count} ${itemText} moved to review queue (no face match)`,
      ICONS.REVIEW,
      'warning'
    )
  }

  private formatPlatformName(platform: string): string {
    const names: Record<string, string> = {
      fastdl: 'Instagram',
      imginn: 'Instagram',
      toolzu: 'Instagram',
      instagram: 'Instagram',
      tiktok: 'TikTok',
      snapchat: 'Snapchat',
      forum: 'Forum',
    }
    return names[platform.toLowerCase()] || platform.charAt(0).toUpperCase() + platform.slice(1)
  }

  // ============================================
  // Generic API Error Handler
  // ============================================

  /** Show error notification from API response */
  apiError(title: string, err: unknown, fallback?: string) {
    return this.error(title, extractErrorMessage(err, fallback || 'An error occurred'))
  }
}

export const notificationManager = new NotificationManager()
