/**
 * Analytics Integration Service
 * Integrates Time Entries analytics with existing entities for enriched analysis
 */

import { TimeEntry } from '@/lib/types/database';
import { analyticsEngine } from './analytics-engine';
import { llmAnalyzer } from './llm-analyzer';
import { postgresClient } from './postgres-client';
import { 
  TimelineEvent, 
  AnalyticsInsight, 
  AggregateAnalysis,
  LLMAnalysisRequest 
} from '@/lib/types/analytics';

export interface EnrichedTimeEntry extends TimeEntry {
  resource_name?: string;
  ticket_title?: string;
  ticket_number?: string;
  task_title?: string;
  project_name?: string;
  company_name?: string;
  analysis?: {
    activityScore: number;
    contentScore: number;
    timelinessScore: number;
    overallScore: number;
  };
}

export interface EnrichmentOptions {
  includeResourceInfo?: boolean;
  includeTicketInfo?: boolean;
  includeTaskInfo?: boolean;
  includeProjectInfo?: boolean;
  includeCompanyInfo?: boolean;
  includeAnalysis?: boolean;
  includeRelatedEntities?: boolean;
}

export class AnalyticsIntegrationService {
  
  /**
   * Enrich time entries with related entity data and analysis
   */
  async enrichTimeEntries(
    timeEntries: TimeEntry[],
    options: EnrichmentOptions = {}
  ): Promise<EnrichedTimeEntry[]> {
    const enriched: EnrichedTimeEntry[] = [];
    
    // Extract IDs for batch queries
    const resourceIds = [...new Set(timeEntries.map(te => te.resource_id).filter((id): id is number => id != null))];
    const ticketIds = [...new Set(timeEntries.map(te => te.ticket_id).filter((id): id is number => id != null))];
    const taskIds = [...new Set(timeEntries.map(te => te.task_id).filter((id): id is number => id != null))];
    const projectIds = [...new Set(timeEntries.map(te => te.project_id).filter((id): id is number => id != null))];
    const companyIds = [...new Set(timeEntries.map(te => te.company_id).filter((id): id is number => id != null))];
    
    // Batch fetch related entities
    const [resources, tickets, tasks, projects, companies] = await Promise.all([
      options.includeResourceInfo && resourceIds.length > 0 
        ? this.getResources(resourceIds) 
        : Promise.resolve([]),
      options.includeTicketInfo && ticketIds.length > 0 
        ? this.getTickets(ticketIds) 
        : Promise.resolve([]),
      options.includeTaskInfo && taskIds.length > 0 
        ? this.getTasks(taskIds) 
        : Promise.resolve([]),
      options.includeProjectInfo && projectIds.length > 0 
        ? this.getProjects(projectIds) 
        : Promise.resolve([]),
      options.includeCompanyInfo && companyIds.length > 0 
        ? this.getCompanies(companyIds) 
        : Promise.resolve([]),
    ]);
    
    // Create lookup maps
    const resourceMap = new Map(resources.map(r => [r.id, r]));
    const ticketMap = new Map(tickets.map(t => [t.id, t]));
    const taskMap = new Map(tasks.map(t => [t.id, t]));
    const projectMap = new Map(projects.map(p => [p.id, p]));
    const companyMap = new Map(companies.map(c => [c.id, c]));
    
    // Enrich each time entry
    for (const timeEntry of timeEntries) {
      const enrichedEntry: EnrichedTimeEntry = { ...timeEntry };
      
      // Add related entity information
      if (options.includeResourceInfo) {
        const resource = resourceMap.get(timeEntry.resource_id);
        if (resource) {
          enrichedEntry.resource_name = `${resource.first_name} ${resource.last_name}`;
        }
      }
      
      if (options.includeTicketInfo) {
        const ticket = ticketMap.get(timeEntry.ticket_id);
        if (ticket) {
          enrichedEntry.ticket_title = ticket.title;
          enrichedEntry.ticket_number = ticket.ticket_number;
        }
      }
      
      if (options.includeTaskInfo) {
        const task = taskMap.get(timeEntry.task_id);
        if (task) {
          enrichedEntry.task_title = task.title;
        }
      }
      
      if (options.includeProjectInfo) {
        const project = projectMap.get(timeEntry.project_id);
        if (project) {
          enrichedEntry.project_name = project.project_name;
        }
      }
      
      if (options.includeCompanyInfo) {
        const company = companyMap.get(timeEntry.company_id);
        if (company) {
          enrichedEntry.company_name = company.company_name;
        }
      }
      
      // Add analysis
      if (options.includeAnalysis) {
        const analysis = analyticsEngine.analyzeTimeEntry(timeEntry);
        enrichedEntry.analysis = {
          activityScore: analysis.activityScore.score,
          contentScore: analysis.contentScore.score,
          timelinessScore: analysis.timelinessScore.score,
          overallScore: analysis.overallScore,
        };
      }
      
      enriched.push(enrichedEntry);
    }
    
    return enriched;
  }
  
  /**
   * Generate timeline events from enriched time entries
   */
  async generateTimelineEvents(
    timeEntries: TimeEntry[],
    options: EnrichmentOptions = {
      includeResourceInfo: true,
      includeTicketInfo: true,
      includeTaskInfo: true,
      includeProjectInfo: true,
      includeCompanyInfo: true,
    }
  ): Promise<TimelineEvent[]> {
    const enrichedEntries = await this.enrichTimeEntries(timeEntries, options);
    
    const events: TimelineEvent[] = enrichedEntries.map(entry => ({
      id: `te-${entry.id}`,
      type: 'time_entry',
      timestamp: new Date(entry.entry_date),
      title: entry.title || 'Time Entry',
      description: this.generateEventDescription(entry),
      duration: entry.hours_worked,
      metadata: {
        timeEntryId: entry.id,
        resourceId: entry.resource_id,
        resourceName: entry.resource_name,
        ticketId: entry.ticket_id,
        ticketTitle: entry.ticket_title,
        ticketNumber: entry.ticket_number,
        taskId: entry.task_id,
        taskTitle: entry.task_title,
        projectId: entry.project_id,
        projectName: entry.project_name,
        companyId: entry.company_id,
        companyName: entry.company_name,
        billable: entry.billable,
        approved: entry.approved,
        score: entry.analysis?.overallScore,
      },
      score: entry.analysis?.overallScore,
      isHumanActivity: true,
      importance: this.determineImportance(entry),
    }));
    
    // Add key moments if requested
    if (options.includeRelatedEntities) {
      const keyMomentEvents = await this.generateKeyMomentEvents(timeEntries);
      events.push(...keyMomentEvents);
    }
    
    // Sort by timestamp
    return events.sort((a, b) => a.timestamp.getTime() - b.timestamp.getTime());
  }
  
  /**
   * Generate comprehensive analysis with entity context
   */
  async generateComprehensiveAnalysis(
    timeEntries: TimeEntry[],
    options: EnrichmentOptions = {
      includeResourceInfo: true,
      includeTicketInfo: true,
      includeProjectInfo: true,
      includeCompanyInfo: true,
      includeAnalysis: true,
    }
  ): Promise<{
    analysis: AggregateAnalysis;
    enrichedEntries: EnrichedTimeEntry[];
    entityInsights: AnalyticsInsight[];
  }> {
    // Enrich time entries
    const enrichedEntries = await this.enrichTimeEntries(timeEntries, options);
    
    // Generate basic analysis
    const analysis = analyticsEngine.analyzeTimeEntries(timeEntries);
    
    // Generate entity-specific insights
    const entityInsights = await this.generateEntityInsights(enrichedEntries);
    
    // Combine insights
    analysis.insights = [...analysis.insights, ...entityInsights];
    
    return {
      analysis,
      enrichedEntries,
      entityInsights,
    };
  }
  
  /**
   * Generate LLM analysis with enriched context
   */
  async generateLLMAnalysis(
    timeEntries: TimeEntry[],
    analysisType: 'productivity' | 'quality' | 'patterns' | 'anomalies' | 'comprehensive' = 'comprehensive',
    options: EnrichmentOptions = {
      includeResourceInfo: true,
      includeTicketInfo: true,
      includeProjectInfo: true,
      includeCompanyInfo: true,
    }
  ) {
    const enrichedEntries = await this.enrichTimeEntries(timeEntries, options);
    
    const request: LLMAnalysisRequest = {
      timeEntries: enrichedEntries.map(entry => ({
        id: entry.id,
        notes: entry.notes || undefined,
        title: entry.title || undefined,
        hours_worked: entry.hours_worked,
        entry_date: entry.entry_date.toISOString(),
        resource_name: entry.resource_name,
        ticket_title: entry.ticket_title,
      })),
      analysisType,
      context: {
        timeRange: `${new Date().toISOString().split('T')[0]}`,
        resourceIds: [...new Set(enrichedEntries.map(e => e.resource_id).filter((id): id is number => id != null))],
        projectIds: [...new Set(enrichedEntries.map(e => e.project_id).filter((id): id is number => id != null))],
      },
    };
    
    return llmAnalyzer.analyzeTimeEntries(request);
  }
  
  /**
   * Generate entity-specific insights
   */
  private async generateEntityInsights(enrichedEntries: EnrichedTimeEntry[]): Promise<AnalyticsInsight[]> {
    const insights: AnalyticsInsight[] = [];
    
    // Resource-based insights
    const resourceGroups = this.groupBy(enrichedEntries, 'resource_id');
    for (const [resourceId, entries] of Object.entries(resourceGroups)) {
      const resourceName = entries[0]?.resource_name || `Resource ${resourceId}`;
      const avgScore = entries.reduce((sum, e) => sum + (e.analysis?.overallScore || 0), 0) / entries.length;
      
      if (avgScore < 0.5) {
        insights.push({
          type: 'warning',
          category: 'activity',
          title: `Low Performance: ${resourceName}`,
          description: `${resourceName} has an average score of ${(avgScore * 100).toFixed(1)}%`,
          recommendation: 'Review time entry quality and provide training if needed',
          severity: 'medium',
          actionable: true,
        });
      }
    }
    
    // Project-based insights
    const projectGroups = this.groupBy(enrichedEntries, 'project_id');
    for (const [projectId, entries] of Object.entries(projectGroups)) {
      const projectName = entries[0]?.project_name || `Project ${projectId}`;
      const totalHours = entries.reduce((sum, e) => sum + e.hours_worked, 0);
      
      if (totalHours > 100) {
        insights.push({
          type: 'info',
          category: 'performance',
          title: `High Activity: ${projectName}`,
          description: `${Number(totalHours).toFixed(1)} hours logged for this project`,
          recommendation: 'Monitor project progress and resource allocation',
          severity: 'low',
          actionable: true,
        });
      }
    }
    
    // Ticket-based insights
    const ticketGroups = this.groupBy(enrichedEntries, 'ticket_id');
    for (const [ticketId, entries] of Object.entries(ticketGroups)) {
      const ticketTitle = entries[0]?.ticket_title || `Ticket ${ticketId}`;
      const totalHours = entries.reduce((sum, e) => sum + e.hours_worked, 0);
      
      if (totalHours > 20) {
        insights.push({
          type: 'warning',
          category: 'performance',
          title: `Time Intensive: ${ticketTitle}`,
          description: `${Number(totalHours).toFixed(1)} hours logged for this ticket`,
          recommendation: 'Review if ticket scope is appropriate or needs to be split',
          severity: 'medium',
          actionable: true,
        });
      }
    }
    
    return insights;
  }
  
  /**
   * Generate key moment events from related entities
   */
  private async generateKeyMomentEvents(timeEntries: TimeEntry[]): Promise<TimelineEvent[]> {
    const events: TimelineEvent[] = [];
    
    // Get ticket creation and resolution dates
    const ticketIds = [...new Set(timeEntries.map(te => te.ticket_id).filter((id): id is number => id != null))];
    if (ticketIds.length > 0) {
      const tickets = await this.getTickets(ticketIds);
      
      for (const ticket of tickets) {
        // Ticket creation
        if (ticket.create_date) {
          events.push({
            id: `ticket-created-${ticket.id}`,
            type: 'key_moment',
            timestamp: new Date(ticket.create_date),
            title: `Ticket Created: ${ticket.ticket_number}`,
            description: `Ticket "${ticket.title}" was created`,
            metadata: {
              ticketId: ticket.id,
              ticketNumber: ticket.ticket_number,
              ticketTitle: ticket.title,
            },
            isHumanActivity: false,
            importance: 'high',
          });
        }
        
        // Ticket resolution
        if (ticket.completed_date) {
          events.push({
            id: `ticket-resolved-${ticket.id}`,
            type: 'milestone',
            timestamp: new Date(ticket.completed_date),
            title: `Ticket Resolved: ${ticket.ticket_number}`,
            description: `Ticket "${ticket.title}" was resolved`,
            metadata: {
              ticketId: ticket.id,
              ticketNumber: ticket.ticket_number,
              ticketTitle: ticket.title,
            },
            isHumanActivity: false,
            importance: 'critical',
          });
        }
      }
    }
    
    return events;
  }
  
  /**
   * Helper methods
   */
  private async getResources(resourceIds: number[]) {
    const result = await postgresClient.query(
      'SELECT id, first_name, last_name FROM resources WHERE id = ANY($1)',
      [resourceIds]
    );
    return result.rows;
  }
  
  private async getTickets(ticketIds: number[]) {
    const result = await postgresClient.query(
      'SELECT id, ticket_number, title, create_date, completed_date FROM tickets WHERE id = ANY($1)',
      [ticketIds]
    );
    return result.rows;
  }
  
  private async getTasks(taskIds: number[]) {
    const result = await postgresClient.query(
      'SELECT id, title FROM tasks WHERE id = ANY($1)',
      [taskIds]
    );
    return result.rows;
  }
  
  private async getProjects(projectIds: number[]) {
    const result = await postgresClient.query(
      'SELECT id, project_name FROM projects WHERE id = ANY($1)',
      [projectIds]
    );
    return result.rows;
  }
  
  private async getCompanies(companyIds: number[]) {
    const result = await postgresClient.query(
      'SELECT id, company_name FROM companies WHERE id = ANY($1)',
      [companyIds]
    );
    return result.rows;
  }
  
  private generateEventDescription(entry: EnrichedTimeEntry): string {
    const parts: string[] = [];
    
    if (entry.resource_name) {
      parts.push(`${entry.resource_name} worked`);
    }
    
    parts.push(`${entry.hours_worked} hours`);
    
    if (entry.ticket_title) {
      parts.push(`on "${entry.ticket_title}"`);
    }
    
    if (entry.project_name) {
      parts.push(`for project "${entry.project_name}"`);
    }
    
    if (entry.notes) {
      parts.push(`- ${entry.notes}`);
    }
    
    return parts.join(' ');
  }
  
  private determineImportance(entry: EnrichedTimeEntry): 'low' | 'medium' | 'high' | 'critical' {
    if (entry.hours_worked > 8) return 'high';
    if (entry.billable && entry.hours_worked > 4) return 'high';
    if (entry.billable) return 'medium';
    if (entry.hours_worked > 2) return 'medium';
    return 'low';
  }
  
  private groupBy<T>(array: T[], key: keyof T): Record<string, T[]> {
    return array.reduce((groups, item) => {
      const groupKey = String(item[key]);
      if (!groups[groupKey]) {
        groups[groupKey] = [];
      }
      groups[groupKey].push(item);
      return groups;
    }, {} as Record<string, T[]>);
  }
}

// Create singleton instance
export const analyticsIntegration = new AnalyticsIntegrationService();
