import type { App, Component } from 'vue'
import type { ModulePlugin, ServiceToken } from '@/core/types'
import type { RouteRecordRaw } from 'vue-router'
import { container } from '@/core/di-container'
import { eventBus } from '@/core/event-bus'

/**
 * Module service registration configuration
 */
export interface ServiceRegistration {
  token: ServiceToken
  service: any
  initialize?: {
    waitForDependencies?: boolean
    maxRetries?: number
  }
}

/**
 * Module event listener configuration
 */
export interface EventListener {
  event: string
  handler: (event: any) => void
  description?: string
}

/**
 * Module configuration for BaseModulePlugin
 */
export interface BaseModuleConfig {
  /** Module name */
  name: string
  
  /** Module version */
  version: string
  
  /** Required dependencies */
  dependencies?: string[]
  
  /** Services to register in DI container */
  services?: ServiceRegistration[]
  
  /** Components to register globally */
  components?: Record<string, Component>
  
  /** Routes provided by this module */
  routes?: RouteRecordRaw[]
  
  /** Event listeners to set up */
  eventListeners?: EventListener[]
  
  /** Custom installation logic (called after standard setup) */
  onInstall?: (app: App, options?: any) => Promise<void> | void
  
  /** Custom uninstallation logic (called before standard cleanup) */
  onUninstall?: () => Promise<void> | void
  
  /** Re-exports from this module */
  exports?: {
    types?: Record<string, any>
    composables?: Record<string, any>
  }
}

/**
 * Base class for module plugins that provides common registration patterns
 * Eliminates boilerplate code and ensures consistency across modules
 */
export abstract class BaseModulePlugin implements ModulePlugin {
  public readonly name: string
  public readonly version: string
  public readonly dependencies?: string[]
  public readonly routes?: RouteRecordRaw[]
  public readonly components?: Record<string, Component>
  public readonly services?: Record<string, any>
  public readonly composables?: Record<string, any>
  public readonly config?: Record<string, any>
  
  protected moduleConfig: BaseModuleConfig
  protected installedServices: ServiceToken[] = []

  constructor(config: BaseModuleConfig) {
    this.moduleConfig = config
    this.config = config as any // ModulePlugin config compatibility
    this.name = config.name
    this.version = config.version
    this.dependencies = config.dependencies
    this.routes = config.routes
    this.components = config.components
    this.composables = config.exports?.composables
  }

  /**
   * Standard module installation with common patterns
   */
  async install(app: App, options?: any): Promise<void> {
    this.logInstallStart()

    try {
      // 1. Register global components
      await this.registerComponents(app)
      
      // 2. Register and initialize services
      await this.registerServices()
      
      // 3. Set up event listeners
      this.setupEventListeners()
      
      // 4. Call custom installation logic
      if (this.moduleConfig.onInstall) {
        await this.moduleConfig.onInstall(app, options)
      }
      
      this.logInstallComplete()
      
    } catch (error) {
      console.error(`❌ Failed to install ${this.name} module:`, error)
      throw error
    }
  }

  /**
   * Standard module uninstallation with cleanup
   */
  async uninstall(): Promise<void> {
    this.logUninstallStart()

    try {
      // 1. Call custom uninstallation logic
      if (this.moduleConfig.onUninstall) {
        await this.moduleConfig.onUninstall()
      }
      
      // 2. Clean up registered services
      this.cleanupServices()
      
      this.logUninstallComplete()
      
    } catch (error) {
      console.error(`❌ Failed to uninstall ${this.name} module:`, error)
    }
  }

  /**
   * Register components globally with the Vue app
   */
  protected async registerComponents(app: App): Promise<void> {
    if (!this.moduleConfig.components) return
    
    for (const [name, component] of Object.entries(this.moduleConfig.components)) {
      app.component(name, component)
    }
  }

  /**
   * Register and initialize services in the DI container
   */
  protected async registerServices(): Promise<void> {
    if (!this.moduleConfig.services) return

    for (const serviceConfig of this.moduleConfig.services) {
      // Register service in DI container
      container.provide(serviceConfig.token, serviceConfig.service)
      this.installedServices.push(serviceConfig.token)
      
      // Initialize service if it has an initialize method and config
      if (serviceConfig.initialize && serviceConfig.service.initialize) {
        try {
          await serviceConfig.service.initialize(serviceConfig.initialize)
        } catch (error) {
          console.warn(`⚠️ ${this.name} service initialization deferred:`, error)
          // Service will auto-initialize when dependencies are available
        }
      }
    }
  }

  /**
   * Set up event listeners for inter-module communication
   */
  protected setupEventListeners(): void {
    // Set up standard auth logout listener for all modules
    eventBus.on('auth:logout', () => {
      this.handleAuthLogout()
    })

    // Set up custom event listeners
    if (this.moduleConfig.eventListeners) {
      for (const listener of this.moduleConfig.eventListeners) {
        eventBus.on(listener.event, listener.handler)
      }
    }
  }

  /**
   * Handle authentication logout (override in subclasses if needed)
   */
  protected handleAuthLogout(): void {
    console.log(`${this.name} module: user logged out`)
    // Default behavior - can be overridden by individual modules
  }

  /**
   * Clean up registered services
   */
  protected cleanupServices(): void {
    for (const token of this.installedServices) {
      container.remove(token)
    }
    this.installedServices = []
  }

  /**
   * Logging helpers with consistent emoji patterns
   */
  protected logInstallStart(): void {
    const emoji = this.getModuleEmoji()
    console.log(`${emoji} Installing ${this.name} module...`)
  }

  protected logInstallComplete(): void {
    console.log(`✅ ${this.name} module installed successfully`)
  }

  protected logUninstallStart(): void {
    console.log(`🗑️ Uninstalling ${this.name} module...`)
  }

  protected logUninstallComplete(): void {
    console.log(`✅ ${this.name} module uninstalled`)
  }

  /**
   * Get emoji for this module type (override in subclasses)
   */
  protected getModuleEmoji(): string {
    const emojiMap: Record<string, string> = {
      'chat': '💬',
      'market': '🛒', 
      'events': '🎫',
      'nostr-feed': '📰',
      'base': '🔧'
    }
    return emojiMap[this.name] || '🔌'
  }
}

/**
 * Helper function to create a module plugin from configuration
 * Eliminates the need for boilerplate class definitions
 */
export function createModulePlugin(config: BaseModuleConfig): ModulePlugin {
  return new (class extends BaseModulePlugin {
    constructor() {
      super(config)
    }
  })()
}