import db from '../config/database';
import { logger } from '../utils/logger';
import AutoPilotService, { AutopilotSession, AutopilotConfig } from './AutoPilotService';
import { LogType, TaskStatus } from '../types/enums';

interface ScheduledTask {
  id: string;
  sessionId: string;
  taskType: string;
  cronExpression: string;
  enabled: boolean;
  lastRun: Date | null;
  nextRun: Date | null;
}

interface TaskSchedule {
  taskType: string;
  intervalMinutes: number;
  enabled: boolean;
}

const DEFAULT_SCHEDULES: TaskSchedule[] = [
  { taskType: 'PRICE_ADJUSTMENT', intervalMinutes: 60, enabled: true },
  { taskType: 'INVENTORY_CHECK', intervalMinutes: 30, enabled: true },
  { taskType: 'AD_OPTIMIZATION', intervalMinutes: 120, enabled: true },
  { taskType: 'ORDER_FULFILLMENT', intervalMinutes: 15, enabled: true },
  { taskType: 'CUSTOMER_SERVICE', intervalMinutes: 10, enabled: true }
];

export class AutoPilotScheduler {
  private static instance: AutoPilotScheduler;
  private intervals: Map<string, NodeJS.Timeout> = new Map();
  private isRunning: boolean = false;
  private checkInterval: NodeJS.Timeout | null = null;

  private constructor() {}

  static getInstance(): AutoPilotScheduler {
    if (!AutoPilotScheduler.instance) {
      AutoPilotScheduler.instance = new AutoPilotScheduler();
    }
    return AutoPilotScheduler.instance;
  }

  start(): void {
    if (this.isRunning) {
      logger.warn('[AutoPilotScheduler] Scheduler is already running');
      return;
    }

    this.isRunning = true;
    logger.info('[AutoPilotScheduler] Starting autopilot scheduler');

    this.checkInterval = setInterval(() => {
      this.processActiveSessions();
    }, 60000);

    this.processActiveSessions();

    logger.info('[AutoPilotScheduler] Scheduler started successfully');
  }

  stop(): void {
    if (!this.isRunning) {
      logger.warn('[AutoPilotScheduler] Scheduler is not running');
      return;
    }

    this.isRunning = false;

    if (this.checkInterval) {
      clearInterval(this.checkInterval);
      this.checkInterval = null;
    }

    for (const [sessionId, interval] of this.intervals) {
      clearInterval(interval);
      logger.info(`[AutoPilotScheduler] Cleared interval for session ${sessionId}`);
    }
    this.intervals.clear();

    logger.info('[AutoPilotScheduler] Scheduler stopped');
  }

  async scheduleSession(sessionId: string): Promise<void> {
    const session = await AutoPilotService.getSessionById(sessionId);
    if (!session) {
      throw new Error('Session not found');
    }

    if (this.intervals.has(sessionId)) {
      logger.warn(`[AutoPilotScheduler] Session ${sessionId} is already scheduled`);
      return;
    }

    const config = session.config as AutopilotConfig;
    const enabledFeatures = session.enabled_features;

    const schedules = DEFAULT_SCHEDULES.filter(s => 
      enabledFeatures.includes(this.featureToTaskType(s.taskType))
    );

    const minInterval = Math.min(...schedules.map(s => s.intervalMinutes));
    const intervalMs = minInterval * 60 * 1000;

    const interval = setInterval(async () => {
      await this.executeScheduledTasks(sessionId, schedules);
    }, intervalMs);

    this.intervals.set(sessionId, interval);
    logger.info(`[AutoPilotScheduler] Scheduled session ${sessionId} with ${schedules.length} tasks`);

    await AutoPilotService.logActivity({
      session_id: sessionId,
      tenant_id: session.tenant_id,
      log_type: LogType.INFO,
      task_type: null,
      task_status: TaskStatus.COMPLETED,
      description: `Session scheduled with ${schedules.length} automated tasks`,
      input_data: { schedules: schedules.map(s => s.taskType) },
      output_data: null,
      error_details: null,
      duration_ms: 0,
      is_auto_executed: true,
      trace_id: null
    });
  }

  async unscheduleSession(sessionId: string): Promise<void> {
    const interval = this.intervals.get(sessionId);
    if (interval) {
      clearInterval(interval);
      this.intervals.delete(sessionId);
      logger.info(`[AutoPilotScheduler] Unscheduled session ${sessionId}`);
    }
  }

  private async processActiveSessions(): Promise<void> {
    try {
      const activeSessions = await db('cf_autopilot_sessions')
        .where('status', 'RUNNING')
        .select('*');

      for (const sessionData of activeSessions) {
        const session = {
          id: sessionData.id,
          tenant_id: sessionData.tenant_id,
          shop_id: sessionData.shop_id,
          status: sessionData.status,
          mode: sessionData.mode,
          config: typeof sessionData.config === 'string' ? JSON.parse(sessionData.config) : sessionData.config,
          enabled_features: typeof sessionData.enabled_features === 'string' ? JSON.parse(sessionData.enabled_features) : sessionData.enabled_features,
          total_revenue: parseFloat(sessionData.total_revenue) || 0,
          total_orders: parseInt(sessionData.total_orders) || 0,
          total_profit: parseFloat(sessionData.total_profit) || 0,
          tasks_completed: sessionData.tasks_completed || 0,
          tasks_failed: sessionData.tasks_failed || 0,
          started_at: sessionData.started_at,
          stopped_at: sessionData.stopped_at,
          last_activity_at: sessionData.last_activity_at,
          error_message: sessionData.error_message,
          created_at: sessionData.created_at,
          updated_at: sessionData.updated_at
        };

        if (!this.intervals.has(session.id)) {
          await this.scheduleSession(session.id);
        }

        await this.checkSessionHealth(session as AutopilotSession);
      }
    } catch (error) {
      logger.error('[AutoPilotScheduler] Error processing active sessions:', error);
    }
  }

  private async executeScheduledTasks(sessionId: string, schedules: TaskSchedule[]): Promise<void> {
    const session = await AutoPilotService.getSessionById(sessionId);
    if (!session || session.status !== 'RUNNING') {
      logger.warn(`[AutoPilotScheduler] Session ${sessionId} is not running, skipping tasks`);
      return;
    }

    const now = Date.now();

    for (const schedule of schedules) {
      if (!schedule.enabled) continue;

      try {
        const shouldRun = await this.shouldRunTask(sessionId, schedule);
        if (!shouldRun) continue;

        logger.info(`[AutoPilotScheduler] Executing task ${schedule.taskType} for session ${sessionId}`);

        const result = await AutoPilotService.executeTask({
          sessionId,
          taskType: schedule.taskType,
          input: { scheduled: true, timestamp: now },
          isAutoExecuted: true
        });

        if (result.success) {
          await this.updateTaskLastRun(sessionId, schedule.taskType);
        }
      } catch (error: any) {
        logger.error(`[AutoPilotScheduler] Error executing task ${schedule.taskType}:`, error);
      }
    }
  }

  private async shouldRunTask(sessionId: string, schedule: TaskSchedule): Promise<boolean> {
    const lastRun = await this.getTaskLastRun(sessionId, schedule.taskType);
    
    if (!lastRun) return true;

    const intervalMs = schedule.intervalMinutes * 60 * 1000;
    const timeSinceLastRun = Date.now() - new Date(lastRun).getTime();

    return timeSinceLastRun >= intervalMs;
  }

  private async getTaskLastRun(sessionId: string, taskType: string): Promise<Date | null> {
    const log = await db('cf_autopilot_logs')
      .where('session_id', sessionId)
      .where('task_type', taskType)
      .where('task_status', TaskStatus.COMPLETED)
      .orderBy('created_at', 'desc')
      .first();

    return log ? log.created_at : null;
  }

  private async updateTaskLastRun(sessionId: string, taskType: string): Promise<void> {
    logger.info(`[AutoPilotScheduler] Updated last run for ${taskType} in session ${sessionId}`);
  }

  private async checkSessionHealth(session: AutopilotSession): Promise<void> {
    const lastActivity = session.last_activity_at ? new Date(session.last_activity_at).getTime() : 0;
    const timeSinceActivity = Date.now() - lastActivity;
    const maxInactivityMs = 30 * 60 * 1000;

    if (timeSinceActivity > maxInactivityMs) {
      logger.warn(`[AutoPilotScheduler] Session ${session.id} has been inactive for ${Math.round(timeSinceActivity / 60000)} minutes`);

      await AutoPilotService.logActivity({
        session_id: session.id,
        tenant_id: session.tenant_id,
        log_type: LogType.WARNING,
        task_type: null,
        task_status: TaskStatus.PENDING,
        description: 'Session has been inactive for extended period',
        input_data: { inactiveMinutes: Math.round(timeSinceActivity / 60000) },
        output_data: null,
        error_details: null,
        duration_ms: 0,
        is_auto_executed: true,
        trace_id: null
      });
    }
  }

  private featureToTaskType(taskType: string): string {
    const mapping: Record<string, string> = {
      'PRICE_ADJUSTMENT': 'pricing',
      'INVENTORY_CHECK': 'inventory',
      'AD_OPTIMIZATION': 'advertising',
      'ORDER_FULFILLMENT': 'orderFulfillment',
      'CUSTOMER_SERVICE': 'customerService'
    };
    return mapping[taskType] || taskType.toLowerCase();
  }

  getStatus(): { isRunning: boolean; activeSessions: number } {
    return {
      isRunning: this.isRunning,
      activeSessions: this.intervals.size
    };
  }

  async getSessionSchedule(sessionId: string): Promise<TaskSchedule[]> {
    const session = await AutoPilotService.getSessionById(sessionId);
    if (!session) {
      return [];
    }

    const enabledFeatures = session.enabled_features;
    return DEFAULT_SCHEDULES.filter(s => 
      enabledFeatures.includes(this.featureToTaskType(s.taskType))
    );
  }

  updateTaskSchedule(sessionId: string, taskType: string, intervalMinutes: number): void {
    logger.info(`[AutoPilotScheduler] Updated schedule for ${taskType} in session ${sessionId} to ${intervalMinutes} minutes`);
  }
}

export default AutoPilotScheduler.getInstance();
