// Types
export * from './types';

// Services
export * from './services';

// Components
export * from './components';

// Feature Module Plugin
import { IPlugin, ServiceConfig, PluginMetadata, RouteConfig, ComponentConfig } from '../../core/interfaces/IPlugin';
import { RewardService, WalletService, PayrollCalculator } from './services';
import { MockRewardRepository } from './repositories';
import { EventBus } from '../../core/events/EventBus';
import { RewardDashboard } from './components/RewardDashboard';
import { WalletBalance } from './components/WalletBalance';
import { PayrollManagement } from './components/PayrollManagement';
import { container as globalContainer } from '../../core/di/DIContainer';

export class PayrollRewardSystemModule implements IPlugin {
  readonly metadata: PluginMetadata = {
    id: 'payroll-reward-system',
    name: 'Payroll Reward System',
    version: '1.0.0',
    description: 'Comprehensive payroll and reward management system for LMS participants'
  };

  private isActive = false;
  private eventBus: EventBus;
  private rewardRepository: MockRewardRepository;
  private rewardService: RewardService;
  private walletService: WalletService;
  private payrollCalculator: PayrollCalculator | undefined;
  private services: Map<string, any> = new Map();

  constructor() {
    this.eventBus = new EventBus();
    this.rewardRepository = new MockRewardRepository();
    this.rewardService = new RewardService(this.rewardRepository, this.eventBus);
    this.walletService = new WalletService();
    this.payrollCalculator = undefined;
    this.isActive = false;
  }

  async activate(): Promise<void> {
    if (this.isActive) return;
  
    // Initialize services
    await this.rewardService.initialize();
    await this.walletService.initialize();
  
    // Register reward-service to DIContainer first
    this.services.set('reward-service', this.rewardService);
    this.services.set('wallet-service', this.walletService);
    // Register the already-initialized instances to the global DI container
    globalContainer.registerInstance('reward-service', this.rewardService);
    globalContainer.registerInstance('wallet-service', this.walletService);
    // Baru inisialisasi PayrollCalculator setelah reward-service terdaftar
    // Use resolveSync because reward-service is already registered as an instance
    this.payrollCalculator = new PayrollCalculator(() => globalContainer.resolveSync('reward-service'));
    await this.payrollCalculator.initialize();
    this.services.set('payroll-calculator', this.payrollCalculator);
  
    this.isActive = true;
    console.log(`${this.metadata.name} module activated`);
  }

  async deactivate(): Promise<void> {
    if (!this.isActive) return;

    // Cleanup services
    this.services.forEach(async (service, id) => {
      if (service.destroy) {
        await service.destroy();
      }
    });
    
    this.services.clear();
    this.isActive = false;
    console.log(`${this.metadata.name} module deactivated`);
  }

  getRoutes(): RouteConfig[] {
    return [
      {
        path: '/rewards',
        component: RewardDashboard,
        permissions: ['view_rewards']
      },
      {
        path: '/wallet',
        component: WalletBalance,
        permissions: ['view_wallet']
      },
      {
        path: '/admin/payroll',
        component: PayrollManagement,
        permissions: ['manage_payroll']
      }
    ];
  }

  getComponents(): ComponentConfig {
    return {
      RewardDashboard,
      WalletBalance,
      PayrollManagement
    };
  }

  getServices(): ServiceConfig[] {
    if (!this.isActive) {
      console.warn('PayrollRewardSystemModule is not active. Call activate() first.');
      return [];
    }
    
    return [
      {
        token: 'reward-service',
        factory: () => this.rewardService,
        singleton: true
      },
      {
        token: 'wallet-service',
        factory: () => this.walletService,
        singleton: true
      },
      {
        token: 'payroll-calculator',
        factory: () => {
          if (!this.payrollCalculator) {
            throw new Error('PayrollCalculator not initialized. Make sure to call activate() first.');
          }
          return this.payrollCalculator;
        },
        singleton: true
      }
    ];
  }

  async isHealthy(): Promise<boolean> {
    if (!this.isActive) return false;

    try {
      const healthChecks: Promise<boolean>[] = [];
      this.services.forEach((service, id) => {
        if (service.isHealthy) {
          healthChecks.push(
            service.isHealthy().then((healthy: boolean) => {
              if (!healthy) {
                console.warn(`Service ${id} is not healthy`);
              }
              return healthy;
            })
          );
        }
      });
      
      const results = await Promise.all(healthChecks);
      return results.every((result: boolean) => result);
    } catch (error) {
      console.error('Health check failed:', error);
      return false;
    }
  }

  getConfiguration() {
    return {
      features: {
        rewards: true,
        wallet: true,
        payroll: true
      },
      settings: {
        currency: 'IDR',
        minimumPayoutAmount: 50000,
        payrollFrequency: 'monthly'
      }
    };
  }

  async install(): Promise<void> {
    console.log(`Installing ${this.metadata.name} module...`);
    // In a real implementation, this would:
    // - Create database tables
    // - Set up initial configurations
    // - Register permissions
    // - Create default reward configs
  }

  async uninstall(): Promise<void> {
    console.log(`Uninstalling ${this.metadata.name} module...`);
    await this.deactivate();
    // In a real implementation, this would:
    // - Clean up database tables
    // - Remove configurations
    // - Revoke permissions
  }

  async migrate(fromVersion: string, toVersion: string): Promise<void> {
    console.log(`Migrating ${this.metadata.name} from ${fromVersion} to ${toVersion}...`);
    // In a real implementation, this would handle data migrations
  }
}

// Export singleton instance
export const payrollRewardSystemModule = new PayrollRewardSystemModule();