import {
  ProcessDefinition,
  TriggerSuggestion,
  ProcessTrigger,
  TriggerPattern,
  TriggerTemplate,
  PersonaType,
  Activity,
  TriggerConflict
} from './types.js';
import { ProcessStore } from './process-store.js';

export class TriggerSuggestionEngine {
  private store: ProcessStore;
  private patterns: Map<PersonaType, TriggerPattern[]> = new Map();

  constructor(store: ProcessStore) {
    this.store = store;
    this.initializePatterns();
  }

  async suggestTriggers(process: ProcessDefinition): Promise<TriggerSuggestion[]> {
    const suggestions: TriggerSuggestion[] = [];
    
    // Analyze activities to understand the process
    const activityAnalysis = this.analyzeActivities(process.activities);
    
    // Get persona-specific patterns
    const personaPatterns = process.persona 
      ? this.patterns.get(process.persona) || []
      : [];
    
    // Generate primary suggestions based on activity patterns
    const primarySuggestion = await this.generatePrimarySuggestion(
      process,
      activityAnalysis,
      personaPatterns
    );
    
    if (primarySuggestion) {
      suggestions.push(primarySuggestion);
    }
    
    // Generate alternative suggestions
    const alternatives = await this.generateAlternatives(
      process,
      activityAnalysis,
      primarySuggestion
    );
    
    suggestions.push(...alternatives);
    
    // Check for conflicts with existing processes
    for (const suggestion of suggestions) {
      suggestion.conflicts = await this.detectConflicts(suggestion.trigger);
    }
    
    return suggestions.sort((a, b) => b.confidence - a.confidence);
  }

  private analyzeActivities(activities: Activity[]): ActivityAnalysis {
    const analysis: ActivityAnalysis = {
      types: new Set(),
      hasHumanInteraction: false,
      hasExternalCalls: false,
      estimatedDuration: 0,
      isReportGeneration: false,
      isDataProcessing: false,
      isReview: false,
      isContinuous: false
    };

    for (const activity of activities) {
      analysis.types.add(activity.type);
      
      if (activity.type === 'human') {
        analysis.hasHumanInteraction = true;
      }
      
      if (activity.type === 'external') {
        analysis.hasExternalCalls = true;
      }
      
      // Detect patterns from activity names
      const nameLower = activity.name.toLowerCase();
      if (nameLower.includes('report') || nameLower.includes('summary')) {
        analysis.isReportGeneration = true;
      }
      if (nameLower.includes('process') || nameLower.includes('analyze') || 
          nameLower.includes('extract') || nameLower.includes('transform') || 
          nameLower.includes('load') || nameLower.includes('etl')) {
        analysis.isDataProcessing = true;
      }
      if (nameLower.includes('review') || nameLower.includes('check')) {
        analysis.isReview = true;
      }
      if (nameLower.includes('monitor') || nameLower.includes('watch')) {
        analysis.isContinuous = true;
      }
    }

    return analysis;
  }

  private async generatePrimarySuggestion(
    process: ProcessDefinition,
    analysis: ActivityAnalysis,
    personaPatterns: TriggerPattern[]
  ): Promise<TriggerSuggestion | null> {
    let trigger: ProcessTrigger | null = null;
    let confidence = 0;
    let reasoning = '';

    // Check persona patterns first
    if (personaPatterns.length > 0 && personaPatterns[0].suggestedTriggers.length > 0) {
      const personaTrigger = personaPatterns[0].suggestedTriggers[0];
      trigger = this.createTriggerFromTemplate(personaTrigger);
      confidence = 0.85;
      reasoning = personaTrigger.applicableWhen || 'Based on persona-specific patterns';
    }
    // Check for continuous monitoring pattern
    else if (analysis.isContinuous) {
      trigger = this.createScheduleTrigger(
        'Continuous Monitoring',
        '*/15 * * * *', // Every 15 minutes
        'UTC'
      );
      confidence = 0.9;
      reasoning = 'Continuous monitoring processes should run frequently to catch issues quickly';
    }
    // Check for report generation pattern
    else if (analysis.isReportGeneration) {
      const schedule = this.determineReportSchedule(process.name);
      trigger = this.createScheduleTrigger(
        'Report Generation Schedule',
        schedule.cron,
        schedule.timezone
      );
      confidence = 0.85;
      reasoning = `Report generation typically follows a ${schedule.description} schedule`;
    }
    // Check for review/approval processes
    else if (analysis.isReview && analysis.hasHumanInteraction) {
      trigger = this.createScheduleTrigger(
        'Review Cycle',
        '0 9 * * 1-5', // Weekdays at 9 AM
        'UTC'
      );
      confidence = 0.8;
      reasoning = 'Review processes work best during business hours when team members are available';
    }
    // Check persona-specific patterns
    else if (personaPatterns.length > 0) {
      const bestPattern = this.findBestPattern(personaPatterns, analysis);
      if (bestPattern) {
        trigger = this.createTriggerFromTemplate(bestPattern.suggestedTriggers[0]);
        confidence = 0.75;
        reasoning = `Common pattern for ${process.persona} persona: ${bestPattern.suggestedTriggers[0].applicableWhen}`;
      }
    }

    if (!trigger) {
      // Default to manual trigger
      trigger = this.createManualTrigger();
      confidence = 0.5;
      reasoning = 'No clear pattern detected, manual trigger provides maximum flexibility';
    }

    return {
      trigger: { ...trigger, aiSuggested: true, reasoning },
      confidence,
      reasoning,
      alternatives: []
    };
  }

  private async generateAlternatives(
    process: ProcessDefinition,
    analysis: ActivityAnalysis,
    primarySuggestion: TriggerSuggestion | null
  ): Promise<TriggerSuggestion[]> {
    const alternatives: TriggerSuggestion[] = [];

    // Add persona-specific alternatives
    if (process.persona) {
      const personaPatterns = this.patterns.get(process.persona) || [];
      for (const pattern of personaPatterns) {
        for (let i = 1; i < pattern.suggestedTriggers.length; i++) {
          const template = pattern.suggestedTriggers[i];
          if (!primarySuggestion || template.type !== primarySuggestion.trigger.type) {
            const trigger = this.createTriggerFromTemplate(template);
            alternatives.push({
              trigger: { ...trigger, aiSuggested: true },
              confidence: 0.75,
              reasoning: template.applicableWhen || 'Based on persona-specific patterns',
              alternatives: []
            });
          }
        }
      }
    }

    // Event-based alternative for processes that might react to changes
    if (analysis.hasExternalCalls || analysis.isDataProcessing) {
      const eventTrigger = this.createEventTrigger(
        'Data Change Event',
        'data.updated',
        'system'
      );
      
      alternatives.push({
        trigger: { ...eventTrigger, aiSuggested: true },
        confidence: 0.7,
        reasoning: 'Trigger immediately when relevant data changes for real-time processing',
        alternatives: []
      });
    }

    // Scheduled batch alternative
    if (!primarySuggestion || primarySuggestion.trigger.type !== 'schedule') {
      const batchSchedule = this.determineBatchSchedule(analysis);
      const scheduleTrigger = this.createScheduleTrigger(
        'Batch Processing',
        batchSchedule.cron,
        batchSchedule.timezone
      );
      
      alternatives.push({
        trigger: { ...scheduleTrigger, aiSuggested: true },
        confidence: 0.65,
        reasoning: `Batch processing ${batchSchedule.description} for efficiency`,
        alternatives: []
      });
    }

    // Manual with reminder
    if (analysis.hasHumanInteraction) {
      const manualTrigger = this.createManualTrigger('Manual with Reminder');
      
      alternatives.push({
        trigger: { ...manualTrigger, aiSuggested: true },
        confidence: 0.6,
        reasoning: 'Human-centric processes benefit from manual triggers with email reminders',
        alternatives: []
      });
    }

    return alternatives;
  }

  private async detectConflicts(trigger: ProcessTrigger): Promise<TriggerConflict[]> {
    const conflicts: TriggerConflict[] = [];
    
    if (trigger.type === 'schedule' && trigger.config.cron) {
      // Get all processes with schedule triggers
      const processes = await this.store.getAllProcesses();
      
      for (const process of processes) {
        for (const existingTrigger of process.triggers) {
          if (
            existingTrigger.type === 'schedule' && 
            existingTrigger.config.cron &&
            this.hasScheduleOverlap(trigger.config.cron, existingTrigger.config.cron)
          ) {
            conflicts.push({
              processId: process.id,
              processName: process.name,
              triggerName: existingTrigger.name,
              conflictType: 'time',
              description: `Both processes scheduled at similar times`,
              suggestion: 'Consider offsetting schedules by 30 minutes'
            });
          }
        }
      }
    }
    
    return conflicts;
  }

  private hasScheduleOverlap(cron1: string, cron2: string): boolean {
    // Simplified overlap detection
    // In a real implementation, use a cron parser
    return cron1 === cron2;
  }

  private determineReportSchedule(processName: string): ScheduleInfo {
    const nameLower = processName.toLowerCase();
    
    if (nameLower.includes('daily')) {
      return {
        cron: '0 8 * * *',
        timezone: 'UTC',
        description: 'daily'
      };
    } else if (nameLower.includes('weekly')) {
      return {
        cron: '0 8 * * 1',
        timezone: 'UTC',
        description: 'weekly (Monday mornings)'
      };
    } else if (nameLower.includes('monthly')) {
      return {
        cron: '0 8 1 * *',
        timezone: 'UTC',
        description: 'monthly (first day of month)'
      };
    }
    
    // Default to weekly
    return {
      cron: '0 8 * * 5',
      timezone: 'UTC',
      description: 'weekly (Friday mornings)'
    };
  }

  private determineBatchSchedule(analysis: ActivityAnalysis): ScheduleInfo {
    if (analysis.estimatedDuration > 3600000) { // > 1 hour
      return {
        cron: '0 2 * * *',
        timezone: 'UTC',
        description: 'nightly at 2 AM when system load is low'
      };
    } else if (analysis.hasExternalCalls) {
      return {
        cron: '0 */4 * * *',
        timezone: 'UTC',
        description: 'every 4 hours to balance freshness and API limits'
      };
    }
    
    return {
      cron: '0 */2 * * *',
      timezone: 'UTC',
      description: 'every 2 hours for regular updates'
    };
  }

  private findBestPattern(
    patterns: TriggerPattern[],
    analysis: ActivityAnalysis
  ): TriggerPattern | null {
    // Find pattern with most matching activity types
    let bestPattern: TriggerPattern | null = null;
    let bestScore = 0;
    
    for (const pattern of patterns) {
      let score = 0;
      for (const activityType of pattern.activityTypes) {
        if (analysis.types.has(activityType as any)) {
          score++;
        }
      }
      
      if (score > bestScore) {
        bestScore = score;
        bestPattern = pattern;
      }
    }
    
    return bestPattern;
  }

  private createScheduleTrigger(
    name: string,
    cron: string,
    timezone: string
  ): ProcessTrigger {
    return {
      id: this.generateId(),
      type: 'schedule',
      name,
      enabled: true,
      config: {
        cron,
        timezone
      }
    };
  }

  private createEventTrigger(
    name: string,
    event: string,
    source: string
  ): ProcessTrigger {
    return {
      id: this.generateId(),
      type: 'event',
      name,
      enabled: true,
      config: {
        event,
        source
      }
    };
  }

  private createManualTrigger(name: string = 'Manual Trigger'): ProcessTrigger {
    return {
      id: this.generateId(),
      type: 'manual',
      name,
      enabled: true,
      config: {}
    };
  }

  private createTriggerFromTemplate(template: TriggerTemplate): ProcessTrigger {
    return {
      id: this.generateId(),
      type: template.type,
      name: template.name,
      enabled: true,
      config: template.defaultConfig as any
    };
  }

  private generateId(): string {
    return `trigger-${Date.now()}-${Math.random().toString(36).substring(2, 11)}`;
  }

  private initializePatterns(): void {
    // Software Engineer patterns
    this.patterns.set('software-engineer', [
      {
        persona: 'software-engineer',
        activityTypes: ['tool', 'agent'],
        suggestedTriggers: [
          {
            type: 'schedule',
            name: 'Daily Development Routine',
            defaultConfig: { cron: '0 9 * * 1-5', timezone: 'local' },
            applicableWhen: 'Daily development tasks like checking CI/CD, reviewing PRs'
          },
          {
            type: 'event',
            name: 'On Code Push',
            defaultConfig: { event: 'git.push', source: 'repository' },
            applicableWhen: 'Automated checks and workflows triggered by code changes'
          }
        ]
      }
    ]);

    // CTO patterns
    this.patterns.set('cto', [
      {
        persona: 'cto',
        activityTypes: ['tool', 'human'],
        suggestedTriggers: [
          {
            type: 'schedule',
            name: 'Weekly Technical Review',
            defaultConfig: { cron: '0 10 * * 1', timezone: 'local' },
            applicableWhen: 'Weekly review of technical metrics and team performance'
          }
        ]
      }
    ]);

    // CEO patterns
    this.patterns.set('ceo', [
      {
        persona: 'ceo',
        activityTypes: ['tool', 'human', 'external'],
        suggestedTriggers: [
          {
            type: 'schedule',
            name: 'Monthly Business Review',
            defaultConfig: { cron: '0 9 1 * *', timezone: 'local' },
            applicableWhen: 'Monthly business metrics and strategic planning'
          }
        ]
      }
    ]);

    // Add more persona patterns as needed
  }
}

interface ActivityAnalysis {
  types: Set<string>;
  hasHumanInteraction: boolean;
  hasExternalCalls: boolean;
  estimatedDuration: number;
  isReportGeneration: boolean;
  isDataProcessing: boolean;
  isReview: boolean;
  isContinuous: boolean;
}

interface ScheduleInfo {
  cron: string;
  timezone: string;
  description: string;
}