import { ConflictException, Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { FuelRepository } from './fuel.repository';
import { FuelPurchase } from './entities/fuel-purchase.entity';
import { FuelConsumption } from './entities/fuel-consumption.entity';
import { CreateFuelPurchaseDto } from './dto/create-fuel-purchase.dto';

@Injectable()
export class FuelService {
  constructor(
    private readonly fuelRepository: FuelRepository,
    @InjectRepository(FuelPurchase)
    private readonly purchaseRepository: Repository<FuelPurchase>,
  ) {}

  async recordFuelPurchase(dto: CreateFuelPurchaseDto): Promise<FuelPurchase> {
    // Reject a re-submitted receipt for the same vehicle (double-entry guard).
    if (dto.receiptNumber) {
      const duplicate = await this.purchaseRepository.findOne({
        where: { vehicleId: dto.vehicleId, receiptNumber: dto.receiptNumber },
      });
      if (duplicate) {
        throw new ConflictException(
          `A fuel purchase with receipt number ${dto.receiptNumber} already exists for this vehicle`,
        );
      }
    }

    const totalCost = dto.liters * dto.costPerLiter;

    const purchase = this.purchaseRepository.create({
      ...dto,
      totalCost,
    });

    const saved = await this.purchaseRepository.save(purchase);

    // Update monthly consumption
    await this.updateMonthlyConsumption(dto.vehicleId, new Date(dto.purchaseDate));

    return saved;
  }

  async getAllFuelPurchases(): Promise<FuelPurchase[]> {
    return this.purchaseRepository
      .createQueryBuilder('purchase')
      .leftJoinAndSelect('purchase.vehicle', 'vehicle')
      .orderBy('purchase.purchaseDate', 'DESC')
      .getMany();
  }

  async getFuelPurchases(
    vehicleId: string,
    startDate: Date,
    endDate: Date,
  ): Promise<FuelPurchase[]> {
    return this.fuelRepository.findByVehicleAndDateRange(vehicleId, startDate, endDate);
  }

  async getMonthlyConsumption(
    vehicleId: string,
    month: Date,
  ): Promise<FuelConsumption | null> {
    return this.fuelRepository.getMonthlyConsumption(vehicleId, month);
  }

  async getFleetFuelStats(monthsBack: number = 12) {
    const endDate = new Date();
    const startDate = new Date(endDate.getFullYear(), endDate.getMonth() - monthsBack, 1);

    const purchases = await this.purchaseRepository
      .createQueryBuilder('purchase')
      .where('purchase.purchaseDate BETWEEN :startDate AND :endDate', { startDate, endDate })
      .getMany();

    const totalLiters = purchases.reduce((sum: number, p: FuelPurchase) => sum + Number(p.liters), 0);
    const totalCost = purchases.reduce((sum: number, p: FuelPurchase) => sum + Number(p.totalCost), 0);
    const averagePrice = totalLiters > 0 ? totalCost / totalLiters : 0;

    return {
      totalPurchases: purchases.length,
      totalLiters,
      totalCost,
      averagePricePerLiter: averagePrice,
      averageEfficiency: 0, // Placeholder - would need distance data
      dateRange: { startDate, endDate },
    };
  }

  async getVehicleFuelStats(vehicleId: string, monthsBack: number = 12) {
    const endDate = new Date();
    const startDate = new Date(endDate.getFullYear(), endDate.getMonth() - monthsBack, 1);

    const purchases = await this.getFuelPurchases(vehicleId, startDate, endDate);

    const totalLiters = purchases.reduce((sum: number, p: FuelPurchase) => sum + Number(p.liters), 0);
    const totalCost = purchases.reduce((sum: number, p: FuelPurchase) => sum + Number(p.totalCost), 0);
    const averagePrice = totalLiters > 0 ? totalCost / totalLiters : 0;

    return {
      vehicleId,
      totalPurchases: purchases.length,
      totalLiters,
      totalCost,
      averagePricePerLiter: averagePrice,
      dateRange: { startDate, endDate },
    };
  }

  private async updateMonthlyConsumption(vehicleId: string, date: Date): Promise<void> {
    const monthStart = new Date(date.getFullYear(), date.getMonth(), 1);
    const monthEnd = new Date(monthStart.getFullYear(), monthStart.getMonth() + 1, 1);

    const purchases = await this.fuelRepository.findByVehicleAndDateRange(
      vehicleId,
      monthStart,
      monthEnd,
    );

    const totalLiters = purchases.reduce((sum: number, p: FuelPurchase) => sum + Number(p.liters), 0);
    const totalCost = purchases.reduce((sum: number, p: FuelPurchase) => sum + Number(p.totalCost), 0);
    const numberOfPurchases = purchases.length;
    const averageCostPerLiter = totalLiters > 0 ? totalCost / totalLiters : 0;

    await this.fuelRepository.updateMonthlyConsumption(vehicleId, monthStart, {
      totalLiters,
      totalCost,
      numberOfPurchases,
      averageCostPerLiter,
    });
  }
}
