/**
 * Analytics Service
 *
 * Aggregates and provides workflow analytics and statistics.
 */

import { getModels } from '../../models';
import type { WorkflowAnalytics, NodePerformance, TimeSeriesPoint } from './types';
import mongoose from 'mongoose';

// ============================================
// ANALYTICS SERVICE CLASS
// ============================================

export class AnalyticsService {
  /**
   * Get workflow statistics
   */
  async getWorkflowStats(workflowId: string): Promise<WorkflowAnalytics> {
    const { AutomationInstance, AutomationWorkflow } = getModels();

    const workflow = await AutomationWorkflow.findById(workflowId).lean();
    if (!workflow) {
      throw new Error('Workflow not found');
    }

    // Aggregate instance stats
    const stats = await AutomationInstance.aggregate([
      { $match: { workflowId: new mongoose.Types.ObjectId(workflowId) } },
      {
        $group: {
          _id: null,
          totalInstances: { $sum: 1 },
          activeInstances: {
            $sum: { $cond: [{ $in: ['$status', ['pending', 'running', 'paused']] }, 1, 0] },
          },
          completedInstances: {
            $sum: { $cond: [{ $eq: ['$status', 'completed'] }, 1, 0] },
          },
          exitedInstances: {
            $sum: { $cond: [{ $eq: ['$status', 'exited'] }, 1, 0] },
          },
          errorInstances: {
            $sum: { $cond: [{ $eq: ['$status', 'error'] }, 1, 0] },
          },
          avgCompletionTime: {
            $avg: {
              $cond: [
                { $eq: ['$status', 'completed'] },
                { $subtract: ['$completedAt', '$enteredAt'] },
                null,
              ],
            },
          },
          lastTriggeredAt: { $max: '$enteredAt' },
        },
      },
    ]);

    const stat = stats[0] || {
      totalInstances: 0,
      activeInstances: 0,
      completedInstances: 0,
      exitedInstances: 0,
      errorInstances: 0,
      avgCompletionTime: null,
      lastTriggeredAt: null,
    };

    // Calculate completion rate
    const completionRate =
      stat.totalInstances > 0
        ? (stat.completedInstances / stat.totalInstances) * 100
        : 0;

    return {
      workflowId,
      totalInstances: stat.totalInstances,
      activeInstances: stat.activeInstances,
      completedInstances: stat.completedInstances,
      exitedInstances: stat.exitedInstances,
      errorInstances: stat.errorInstances,
      completionRate,
      averageCompletionTime: stat.avgCompletionTime || 0,
      lastTriggeredAt: stat.lastTriggeredAt,
    };
  }

  /**
   * Get node performance metrics
   */
  async getNodePerformance(workflowId: string): Promise<NodePerformance[]> {
    const { AutomationLog } = getModels();

    const performance = await AutomationLog.aggregate([
      { $match: { workflowId: new mongoose.Types.ObjectId(workflowId) } },
      {
        $group: {
          _id: '$nodeId',
          nodeType: { $first: '$nodeType' },
          executions: { $sum: 1 },
          avgDuration: { $avg: '$duration' },
          errors: {
            $sum: { $cond: [{ $eq: ['$status', 'error'] }, 1, 0] },
          },
        },
      },
      {
        $project: {
          nodeId: '$_id',
          nodeType: 1,
          executions: 1,
          avgDuration: { $round: ['$avgDuration', 2] },
          errorRate: {
            $cond: [
              { $eq: ['$executions', 0] },
              0,
              { $round: [{ $multiply: [{ $divide: ['$errors', '$executions'] }, 100] }, 2] },
            ],
          },
        },
      },
      { $sort: { executions: -1 } },
    ]);

    return performance.map((p: any) => ({
      nodeId: p.nodeId,
      nodeType: p.nodeType,
      executions: p.executions,
      avgDuration: p.avgDuration || 0,
      errorRate: p.errorRate || 0,
    }));
  }

  /**
   * Get completion timeline (daily counts)
   */
  async getCompletionTimeline(
    workflowId: string,
    days: number = 30
  ): Promise<TimeSeriesPoint[]> {
    const { AutomationInstance } = getModels();

    const startDate = new Date();
    startDate.setDate(startDate.getDate() - days);

    const timeline = await AutomationInstance.aggregate([
      {
        $match: {
          workflowId: new mongoose.Types.ObjectId(workflowId),
          enteredAt: { $gte: startDate },
        },
      },
      {
        $group: {
          _id: {
            $dateToString: { format: '%Y-%m-%d', date: '$enteredAt' },
          },
          total: { $sum: 1 },
          completed: {
            $sum: { $cond: [{ $eq: ['$status', 'completed'] }, 1, 0] },
          },
        },
      },
      { $sort: { _id: 1 } },
    ]);

    return timeline.map((t: any) => ({
      date: t._id,
      value: t.total,
    }));
  }

  /**
   * Get error timeline (daily error counts)
   */
  async getErrorTimeline(workflowId: string, days: number = 30): Promise<TimeSeriesPoint[]> {
    const { AutomationLog } = getModels();

    const startDate = new Date();
    startDate.setDate(startDate.getDate() - days);

    const timeline = await AutomationLog.aggregate([
      {
        $match: {
          workflowId: new mongoose.Types.ObjectId(workflowId),
          status: 'error',
          timestamp: { $gte: startDate },
        },
      },
      {
        $group: {
          _id: {
            $dateToString: { format: '%Y-%m-%d', date: '$timestamp' },
          },
          errors: { $sum: 1 },
        },
      },
      { $sort: { _id: 1 } },
    ]);

    return timeline.map((t: any) => ({
      date: t._id,
      value: t.errors,
    }));
  }

  /**
   * Get drop-off analysis (where users exit)
   */
  async getDropoffAnalysis(workflowId: string): Promise<{
    nodeId: string;
    nodeType: string;
    exits: number;
    exitReason?: string;
  }[]> {
    const { AutomationInstance } = getModels();

    const dropoffs = await AutomationInstance.aggregate([
      {
        $match: {
          workflowId: new mongoose.Types.ObjectId(workflowId),
          status: 'exited',
        },
      },
      {
        $group: {
          _id: '$currentNodeId',
          count: { $sum: 1 },
          reasons: { $push: '$exitReason' },
        },
      },
      { $sort: { count: -1 } },
    ]);

    // Get node types
    const { AutomationWorkflow } = getModels();
    const workflow = await AutomationWorkflow.findById(workflowId).lean();

    if (!workflow) {
      return [];
    }

    return dropoffs.map((d: any) => {
      const node = workflow.nodes.find((n: any) => n.id === d._id);
      return {
        nodeId: d._id,
        nodeType: node?.type || 'unknown',
        exits: d.count,
        exitReason: d.reasons[0] || undefined,
      };
    });
  }

  /**
   * Get goal conversion rate
   */
  async getGoalConversionRate(workflowId: string): Promise<{
    totalInstances: number;
    goalReached: number;
    conversionRate: number;
  }> {
    const { AutomationInstance } = getModels();

    const result = await AutomationInstance.aggregate([
      { $match: { workflowId: new mongoose.Types.ObjectId(workflowId) } },
      {
        $group: {
          _id: null,
          totalInstances: { $sum: 1 },
          goalReached: {
            $sum: { $cond: [{ $eq: ['$goalReached', true] }, 1, 0] },
          },
        },
      },
    ]);

    const stat = result[0] || { totalInstances: 0, goalReached: 0 };

    return {
      totalInstances: stat.totalInstances,
      goalReached: stat.goalReached,
      conversionRate:
        stat.totalInstances > 0
          ? (stat.goalReached / stat.totalInstances) * 100
          : 0,
    };
  }

  /**
   * Get instance details with execution history
   */
  async getInstanceDetails(instanceId: string): Promise<{
    instance: any;
    logs: any[];
  }> {
    const { AutomationInstance, AutomationLog } = getModels();

    const instance = await AutomationInstance.findById(instanceId).lean();
    if (!instance) {
      throw new Error('Instance not found');
    }

    const logs = await AutomationLog.find({ instanceId })
      .sort({ timestamp: 1 })
      .lean();

    return { instance, logs };
  }

  /**
   * Get company-wide automation dashboard stats
   */
  async getDashboardStats(companyId: string): Promise<{
    totalWorkflows: number;
    activeWorkflows: number;
    totalInstances: number;
    activeInstances: number;
    completedInstances: number;
    errorInstances: number;
    avgCompletionRate: number;
  }> {
    const { AutomationWorkflow, AutomationInstance } = getModels();

    // Get workflow stats
    const workflowStats = await AutomationWorkflow.aggregate([
      { $match: { companyId, deletedAt: null } },
      {
        $group: {
          _id: null,
          totalWorkflows: { $sum: 1 },
          activeWorkflows: {
            $sum: { $cond: [{ $eq: ['$status', 'active'] }, 1, 0] },
          },
        },
      },
    ]);

    // Get instance stats
    const instanceStats = await AutomationInstance.aggregate([
      { $match: { companyId } },
      {
        $group: {
          _id: null,
          totalInstances: { $sum: 1 },
          activeInstances: {
            $sum: { $cond: [{ $in: ['$status', ['pending', 'running', 'paused']] }, 1, 0] },
          },
          completedInstances: {
            $sum: { $cond: [{ $eq: ['$status', 'completed'] }, 1, 0] },
          },
          errorInstances: {
            $sum: { $cond: [{ $eq: ['$status', 'error'] }, 1, 0] },
          },
        },
      },
    ]);

    const wf = workflowStats[0] || { totalWorkflows: 0, activeWorkflows: 0 };
    const inst = instanceStats[0] || {
      totalInstances: 0,
      activeInstances: 0,
      completedInstances: 0,
      errorInstances: 0,
    };

    return {
      totalWorkflows: wf.totalWorkflows,
      activeWorkflows: wf.activeWorkflows,
      totalInstances: inst.totalInstances,
      activeInstances: inst.activeInstances,
      completedInstances: inst.completedInstances,
      errorInstances: inst.errorInstances,
      avgCompletionRate:
        inst.totalInstances > 0
          ? (inst.completedInstances / inst.totalInstances) * 100
          : 0,
    };
  }

  /**
   * Update workflow stats (called after instance status change)
   */
  async updateWorkflowStats(workflowId: string): Promise<void> {
    const { AutomationWorkflow, AutomationInstance } = getModels();

    const stats = await AutomationInstance.aggregate([
      { $match: { workflowId: new mongoose.Types.ObjectId(workflowId) } },
      {
        $group: {
          _id: null,
          totalInstances: { $sum: 1 },
          activeInstances: {
            $sum: { $cond: [{ $in: ['$status', ['pending', 'running', 'paused']] }, 1, 0] },
          },
          completedInstances: {
            $sum: { $cond: [{ $eq: ['$status', 'completed'] }, 1, 0] },
          },
          exitedInstances: {
            $sum: { $cond: [{ $eq: ['$status', 'exited'] }, 1, 0] },
          },
          errorInstances: {
            $sum: { $cond: [{ $eq: ['$status', 'error'] }, 1, 0] },
          },
          avgCompletionTime: {
            $avg: {
              $cond: [
                { $eq: ['$status', 'completed'] },
                { $divide: [{ $subtract: ['$completedAt', '$enteredAt'] }, 1000] }, // seconds
                null,
              ],
            },
          },
          lastTriggeredAt: { $max: '$enteredAt' },
        },
      },
    ]);

    if (stats.length > 0) {
      await AutomationWorkflow.findByIdAndUpdate(workflowId, {
        $set: { stats: stats[0] },
      });
    }
  }
}