import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Order } from '../entities/order.entity';
import { OrderItem } from '../entities/order-item.entity';
import { ProductionLine } from '../entities/production-line.entity';
import { Material } from '../entities/material.entity';
import { MaterialRequirement } from '../entities/material-requirement.entity';
import { QualityCheck } from '../entities/quality-check.entity';
import { Inspection } from '../entities/inspection.entity';
import { Payment } from '../entities/payment.entity';
import { Receipt } from '../entities/receipt.entity';
import { ConfigService } from '@nestjs/config';

@Injectable()
export class AnalyticsService {
  constructor(
    @InjectRepository(Order)
    private orderRepository: Repository<Order>,
    @InjectRepository(OrderItem)
    private orderItemRepository: Repository<OrderItem>,
    @InjectRepository(ProductionLine)
    private productionLineRepository: Repository<ProductionLine>,
    @InjectRepository(Material)
    private materialRepository: Repository<Material>,
    @InjectRepository(MaterialRequirement)
    private materialRequirementRepository: Repository<MaterialRequirement>,
    @InjectRepository(QualityCheck)
    private qualityCheckRepository: Repository<QualityCheck>,
    @InjectRepository(Inspection)
    private inspectionRepository: Repository<Inspection>,
    @InjectRepository(Payment)
    private paymentRepository: Repository<Payment>,
    @InjectRepository(Receipt)
    private receiptRepository: Repository<Receipt>,
    private configService: ConfigService,
  ) {}

  async getProductionMetrics(): Promise<any> {
    const [totalOrders, completedOrders, pendingOrders, averageCompletionTime] = await Promise.all([
      this.orderRepository.count(),
      this.orderRepository.count({ where: { status: 'completed' } }),
      this.orderRepository.count({ where: { status: 'pending' } }),
      this.orderRepository
        .createQueryBuilder('order')
        .where('order.status = :status', { status: 'completed' })
        .select("AVG(DATE_PART('day', order.completedAt - order.createdAt))", 'avgDays')
        .getRawOne(),
    ]);

    const totalRevenue = await this.orderRepository
      .createQueryBuilder('order')
      .select('SUM(order.totalAmount)', 'total')
      .getRawOne();

    const productionLines = await this.productionLineRepository.find();

    // Fetch all order items and group by productionLineId
    const allOrderItems = await this.orderItemRepository.find();

    const utilizationRate = productionLines.reduce((sum, line) => {
      const capacity = line.capacity;
      const activeItems = allOrderItems.filter(
        item => item.productionLineId === line.id && item.status === 'in_progress'
      ).length;
      return sum + (activeItems / capacity) * 100;
    }, 0) / productionLines.length;

    const qualityStats = await this.qualityCheckRepository.createQueryBuilder('check')
      .select([
        'check.status',
        'COUNT(check.id) as count',
      ])
      .groupBy('check.status')
      .getRawMany();

    return {
      totalOrders,
      completedOrders,
      pendingOrders,
      totalRevenue: totalRevenue.total,
      utilizationRate: Math.round(utilizationRate),
      averageCompletionTime: averageCompletionTime.avgDays,
      qualityStats,
    };
  }

  async getMaterialUsageReport(startDate: Date, endDate: Date): Promise<any[]> {
    return this.materialRequirementRepository
      .createQueryBuilder('requirement')
      .leftJoinAndSelect('requirement.material', 'material')
      .where('requirement.createdAt BETWEEN :start AND :end', {
        start: startDate,
        end: endDate,
      })
      .select([
        'material.name',
        'material.unit',
        'SUM(requirement.quantity) as totalUsage',
        'material.stockQuantity',
        'material.stockQuantity - SUM(requirement.quantity) as remainingStock',
      ])
      .groupBy('material.id')
      .getRawMany();
  }

  async getOrderCompletionReport(): Promise<any[]> {
    return this.orderRepository
      .createQueryBuilder('order')
      .select([
        'order.status',
        'COUNT(order.id) as count',
        'SUM(order.totalAmount) as totalRevenue',
        "DATE_TRUNC('month', order.createdAt) as month",
      ])
      .groupBy('order.status, month')
      .orderBy('month', 'DESC')
      .getRawMany();
  }

  async getProductionLinePerformance(): Promise<any[]> {
    const [lines, inspections] = await Promise.all([
      this.productionLineRepository
        .createQueryBuilder('line')
        .leftJoinAndSelect('line.orderItems', 'item')
        .select([
          'line.name',
          'line.type',
          'COUNT(item.id) as totalOrders',
          'SUM(item.quantity) as totalQuantity',
          'line.capacity',
        ])
        .groupBy('line.id')
        .getRawMany(),
      this.inspectionRepository
        .createQueryBuilder('inspection')
        .leftJoinAndSelect('inspection.qualityCheck', 'check')
        .select([
          'check.productionLineId',
          'COUNT(inspection.id) as totalInspections',
          "SUM(CASE WHEN inspection.status = 'pass' THEN 1 ELSE 0 END) as passedInspections",
        ])
        .groupBy('check.productionLineId')
        .getRawMany(),
    ]);

    return lines.map(line => {
      const inspectionStats = inspections.find(i => i.productionLineId === line.id);
      return {
        ...line,
        inspectionRate: inspectionStats ? (inspectionStats.passedInspections / inspectionStats.totalInspections) * 100 : 0,
      };
    });
  }

  async getMaterialStockReport(): Promise<any[]> {
    return this.materialRepository
      .createQueryBuilder('material')
      .select([
        'material.name',
        'material.unit',
        'material.stockQuantity',
        'material.unitPrice',
        'material.stockQuantity * material.unitPrice as totalValue',
        'material.minStockLevel',
        'CASE WHEN material.stockQuantity < material.minStockLevel THEN true ELSE false END as lowStock',
      ])
      .getRawMany();
  }
}
