
/**
 * Analytics Service
 * Handles data analysis, regional metrics, and performance calculations
 */

import { prisma } from './db';
type Region = "SOUTH_AFRICA" | "AUSTRALIA" | "UNITED_KINGDOM" | "USA";
type Contract = any;
type ContractorReview = any;
// import { Region, Quote, Contract, ContractorReview, ProjectMilestone } from '@prisma/client';

export class AnalyticsService {
  /**
   * Calculate regional quote metrics for a given period
   */
  static async calculateRegionalMetrics(region: Region, period: string) {
    const periodStart = this.getPeriodStart(period);
    const periodEnd = this.getPeriodEnd(period);

    const quotes = await prisma.quote.findMany({
      where: {
        region,
        createdAt: {
          gte: periodStart,
          lte: periodEnd,
        },
      },
      include: {
        contracts: true,
      },
    });

    const totalQuotes = quotes.length;
    const quotesApproved = quotes.filter((q: any) => q.status === 'ACCEPTED').length;
    const quotesRejected = quotes.filter((q: any) => q.status === 'REJECTED').length;
    const quotesExpired = quotes.filter((q: any) => q.status === 'EXPIRED').length;

    const conversionRate = totalQuotes > 0 ? quotesApproved / totalQuotes : 0;
    const approvalRate = totalQuotes > 0 ? quotesApproved / totalQuotes : 0;

    // Calculate average approval time
    const approvedQuotes = quotes.filter((q: any) => q.acceptedAt);
    const avgApprovalTimeMs =
      approvedQuotes.length > 0
        ? approvedQuotes.reduce((sum: number, q: any) => {
            if (q.acceptedAt && q.sentAt) {
              return sum + (q.acceptedAt.getTime() - q.sentAt.getTime());
            }
            return sum;
          }, 0) / approvedQuotes.length
        : 0;
    const avgApprovalTime = avgApprovalTimeMs / (1000 * 60 * 60); // Convert to hours

    // Calculate average quote value
    const avgQuoteValue = totalQuotes > 0 ? quotes.reduce((sum: number, q: any) => sum + q.total, 0) / totalQuotes : 0;
    const totalValue = quotes.reduce((sum: number, q: any) => sum + q.total, 0);

    return {
      region,
      period,
      totalQuotes,
      quotesApproved,
      quotesRejected,
      quotesExpired,
      conversionRate,
      approvalRate,
      avgApprovalTime,
      avgQuoteValue,
      totalValue,
    };
  }

  /**
   * Calculate dispatch metrics
   */
  static async calculateDispatchMetrics(quoteId: string) {
    const quote = await prisma.quote.findUnique({
      where: { id: quoteId },
      include: {
        contracts: true,
      },
    });

    if (!quote || !quote.acceptedAt) {
      return null;
    }

    const contract = quote.contracts?.[0];
    if (!contract) {
      return null;
    }

    // Get project milestones separately
    const milestones = await prisma.projectMilestone.findMany({
      where: { contractId: contract.id },
    });

    // Find dispatch milestone
    const workStartMilestone = milestones.find(
      (m: any) => m.milestone === 'WORK_STARTED'
    );

    let approvalToDispatchDelay = 0;
    let dispatchDelay = 0;
    let onTimeDispatch = true;

    if (workStartMilestone && workStartMilestone.actualDate) {
      // Calculate delay from approval to dispatch
      const delayMs = workStartMilestone.actualDate.getTime() - quote.acceptedAt.getTime();
      approvalToDispatchDelay = delayMs / (1000 * 60); // minutes

      // Check if dispatched on time (target is within 48 hours)
      const targetDispatchTime = new Date(quote.acceptedAt.getTime() + 48 * 60 * 60 * 1000);
      if (workStartMilestone.actualDate > targetDispatchTime) {
        onTimeDispatch = false;
        dispatchDelay = (workStartMilestone.actualDate.getTime() - targetDispatchTime.getTime()) / (1000 * 60);
      }
    }

    return {
      quoteId,
      contractId: contract.id,
      approvalTime: quote.acceptedAt,
      actualDispatchTime: workStartMilestone?.actualDate,
      approvalToDispatchDelay,
      dispatchDelay,
      onTimeDispatch,
      region: quote.region || "SOUTH_AFRICA",
    };
  }

  /**
   * Calculate partner health score
   */
  static async calculatePartnerHealthScore(partnerId: string, period: string) {
    const periodStart = this.getPeriodStart(period);
    const periodEnd = this.getPeriodEnd(period);

    // Get all contracts for this partner in the period
    const contracts = await prisma.contract.findMany({
      where: {
        partnerId,
        createdAt: {
          gte: periodStart,
          lte: periodEnd,
        },
      },
      include: {
        quote: true,
        slaTracking: true,
      },
    });

    const totalJobs = contracts.length;
    if (totalJobs === 0) {
      return null;
    }

    // Calculate on-time completion
    const onTimeJobs = contracts.filter((c: Contract & { actualCompletion: Date | null; completionDate: Date | null }) => {
      if (c.actualCompletion && c.completionDate) {
        return c.actualCompletion <= c.completionDate;
      }
      return false;
    }).length;

    // Calculate quality issues (SLA breaches)
    const qualityIssues = contracts.reduce((sum: number, c: any) => {
      return sum + (c.slaTracking?.filter((s: { status: string }) => s.status === 'BREACHED').length || 0);
    }, 0);

    // Get customer reviews
    const reviews = await prisma.contractorReview.findMany({
      where: {
        contractorId: partnerId,
        createdAt: {
          gte: periodStart,
          lte: periodEnd,
        },
      },
    });

    const avgRating = reviews.length > 0 ? reviews.reduce((sum: number, r: ContractorReview) => sum + r.overallRating, 0) / reviews.length : 0;

    // Calculate component scores (0-100 scale)
    const qualityScore = Math.max(0, 100 - qualityIssues * 10);
    const timelinessScore = totalJobs > 0 ? (onTimeJobs / totalJobs) * 100 : 0;
    const complianceScore = Math.max(0, 100 - qualityIssues * 5);
    const customerSatScore = (avgRating / 5) * 100;
    const communicationScore = customerSatScore * 0.9; // Derived from customer satisfaction

    // Overall health score (weighted average)
    const overallScore =
      qualityScore * 0.25 +
      timelinessScore * 0.25 +
      complianceScore * 0.2 +
      customerSatScore * 0.2 +
      communicationScore * 0.1;

    // Determine health status
    let healthStatus: 'CRITICAL' | 'AT_RISK' | 'NEEDS_ATTENTION' | 'GOOD' | 'EXCELLENT';
    if (overallScore < 40) healthStatus = 'CRITICAL';
    else if (overallScore < 60) healthStatus = 'AT_RISK';
    else if (overallScore < 75) healthStatus = 'NEEDS_ATTENTION';
    else if (overallScore < 90) healthStatus = 'GOOD';
    else healthStatus = 'EXCELLENT';

    return {
      partnerId,
      period,
      overallScore,
      qualityScore,
      timelinessScore,
      complianceScore,
      customerSatScore,
      communicationScore,
      healthStatus,
      totalJobs,
      onTimeJobs,
      qualityIssues,
    };
  }

  /**
   * Calculate payment latency for a contract
   */
  static async calculatePaymentLatency(contractId: string) {
    const contract = await prisma.contract.findUnique({
      where: { id: contractId },
      include: {
        quote: true,
      },
    });

    if (!contract || !contract.quote) {
      return null;
    }

    const quote = contract.quote;

    // Calculate latencies in hours
    const quoteCreatedAt = quote.createdAt;
    const quoteApprovedAt = quote.acceptedAt;
    const dispatchedAt = contract.startDate;
    const completedAt = contract.actualCompletion;
    const paymentReceivedAt = contract.status === 'COMPLETED' ? contract.actualCompletion : null;

    const quoteToApproval =
      quoteApprovedAt && quoteCreatedAt
        ? (quoteApprovedAt.getTime() - quoteCreatedAt.getTime()) / (1000 * 60 * 60)
        : null;

    const approvalToDispatch =
      dispatchedAt && quoteApprovedAt
        ? (dispatchedAt.getTime() - quoteApprovedAt.getTime()) / (1000 * 60 * 60)
        : null;

    const dispatchToCompletion =
      completedAt && dispatchedAt ? (completedAt.getTime() - dispatchedAt.getTime()) / (1000 * 60 * 60) : null;

    const completionToPayment =
      paymentReceivedAt && completedAt
        ? (paymentReceivedAt.getTime() - completedAt.getTime()) / (1000 * 60 * 60)
        : null;

    const totalLatency =
      [quoteToApproval, approvalToDispatch, dispatchToCompletion, completionToPayment]
        .filter((v): v is number => v !== null)
        .reduce((sum, v) => sum + v, 0) || null;

    return {
      contractId,
      quoteId: quote.id,
      quoteCreatedAt,
      quoteApprovedAt,
      dispatchedAt,
      completedAt,
      paymentReceivedAt,
      quoteToApproval,
      approvalToDispatch,
      dispatchToCompletion,
      completionToPayment,
      totalLatency,
      region: quote.region || "SOUTH_AFRICA",
    };
  }

  /**
   * Helper: Get period start date
   */
  private static getPeriodStart(period: string): Date {
    const now = new Date();
    if (period.includes('-Q')) {
      // Quarterly format: YYYY-Q1
      const [year, quarter] = period.split('-Q');
      const month = (parseInt(quarter) - 1) * 3;
      return new Date(parseInt(year), month, 1);
    } else {
      // Monthly format: YYYY-MM
      const [year, month] = period.split('-');
      return new Date(parseInt(year), parseInt(month) - 1, 1);
    }
  }

  /**
   * Helper: Get period end date
   */
  private static getPeriodEnd(period: string): Date {
    const start = this.getPeriodStart(period);
    if (period.includes('-Q')) {
      // End of quarter
      return new Date(start.getFullYear(), start.getMonth() + 3, 0, 23, 59, 59);
    } else {
      // End of month
      return new Date(start.getFullYear(), start.getMonth() + 1, 0, 23, 59, 59);
    }
  }
}
