/**
 * Vehicle Service
 * Mecánicas Diesel - ERP Suite
 *
 * Business logic for vehicle management.
 */

import { Repository, DataSource } from 'typeorm';
import { Vehicle, VehicleType, VehicleStatus } from '../entities/vehicle.entity';

// DTOs
export interface CreateVehicleDto {
  customerId: string;
  fleetId?: string;
  licensePlate: string;
  vin?: string;
  make: string;
  model: string;
  year: number;
  color?: string;
  vehicleType?: VehicleType;
  economicNumber?: string;
  currentOdometer?: number;
  notes?: string;
}

export interface UpdateVehicleDto {
  licensePlate?: string;
  vin?: string;
  color?: string;
  vehicleType?: VehicleType;
  economicNumber?: string;
  currentOdometer?: number;
  notes?: string;
  status?: VehicleStatus;
}

export interface VehicleFilters {
  customerId?: string;
  fleetId?: string;
  make?: string;
  model?: string;
  year?: number;
  vehicleType?: VehicleType;
  search?: string;
  status?: VehicleStatus;
}

export class VehicleService {
  private vehicleRepository: Repository<Vehicle>;

  constructor(dataSource: DataSource) {
    this.vehicleRepository = dataSource.getRepository(Vehicle);
  }

  /**
   * Create a new vehicle
   */
  async create(tenantId: string, dto: CreateVehicleDto): Promise<Vehicle> {
    // Check for duplicate plate number
    const existing = await this.vehicleRepository.findOne({
      where: { tenantId, licensePlate: dto.licensePlate },
    });

    if (existing) {
      throw new Error(`Vehicle with plate ${dto.licensePlate} already exists`);
    }

    const vehicle = this.vehicleRepository.create({
      tenantId,
      customerId: dto.customerId,
      fleetId: dto.fleetId,
      licensePlate: dto.licensePlate,
      vin: dto.vin,
      make: dto.make,
      model: dto.model,
      year: dto.year,
      color: dto.color,
      vehicleType: dto.vehicleType || VehicleType.TRUCK,
      economicNumber: dto.economicNumber,
      currentOdometer: dto.currentOdometer,
      notes: dto.notes,
      status: VehicleStatus.ACTIVE,
    });

    return this.vehicleRepository.save(vehicle);
  }

  /**
   * Find vehicle by ID
   */
  async findById(tenantId: string, id: string): Promise<Vehicle | null> {
    return this.vehicleRepository.findOne({
      where: { id, tenantId },
    });
  }

  /**
   * Find vehicle by plate number
   */
  async findByPlate(tenantId: string, licensePlate: string): Promise<Vehicle | null> {
    return this.vehicleRepository.findOne({
      where: { tenantId, licensePlate },
    });
  }

  /**
   * Find vehicle by VIN
   */
  async findByVin(tenantId: string, vin: string): Promise<Vehicle | null> {
    return this.vehicleRepository.findOne({
      where: { tenantId, vin },
    });
  }

  /**
   * List vehicles with filters
   */
  async findAll(
    tenantId: string,
    filters: VehicleFilters = {},
    pagination = { page: 1, limit: 20 }
  ) {
    const queryBuilder = this.vehicleRepository.createQueryBuilder('vehicle')
      .where('vehicle.tenant_id = :tenantId', { tenantId });

    if (filters.customerId) {
      queryBuilder.andWhere('vehicle.customer_id = :customerId', { customerId: filters.customerId });
    }
    if (filters.fleetId) {
      queryBuilder.andWhere('vehicle.fleet_id = :fleetId', { fleetId: filters.fleetId });
    }
    if (filters.make) {
      queryBuilder.andWhere('vehicle.make = :make', { make: filters.make });
    }
    if (filters.model) {
      queryBuilder.andWhere('vehicle.model = :model', { model: filters.model });
    }
    if (filters.year) {
      queryBuilder.andWhere('vehicle.year = :year', { year: filters.year });
    }
    if (filters.vehicleType) {
      queryBuilder.andWhere('vehicle.vehicle_type = :vehicleType', { vehicleType: filters.vehicleType });
    }
    if (filters.status) {
      queryBuilder.andWhere('vehicle.status = :status', { status: filters.status });
    }
    if (filters.search) {
      queryBuilder.andWhere(
        '(vehicle.license_plate ILIKE :search OR vehicle.make ILIKE :search OR vehicle.model ILIKE :search OR vehicle.vin ILIKE :search)',
        { search: `%${filters.search}%` }
      );
    }

    const skip = (pagination.page - 1) * pagination.limit;

    const [data, total] = await queryBuilder
      .orderBy('vehicle.created_at', 'DESC')
      .skip(skip)
      .take(pagination.limit)
      .getManyAndCount();

    return {
      data,
      total,
      page: pagination.page,
      limit: pagination.limit,
      totalPages: Math.ceil(total / pagination.limit),
    };
  }

  /**
   * Update vehicle
   */
  async update(tenantId: string, id: string, dto: UpdateVehicleDto): Promise<Vehicle | null> {
    const vehicle = await this.findById(tenantId, id);
    if (!vehicle) return null;

    // Check plate number uniqueness if changing
    if (dto.licensePlate && dto.licensePlate !== vehicle.licensePlate) {
      const existing = await this.findByPlate(tenantId, dto.licensePlate);
      if (existing) {
        throw new Error(`Vehicle with plate ${dto.licensePlate} already exists`);
      }
    }

    Object.assign(vehicle, dto);
    return this.vehicleRepository.save(vehicle);
  }

  /**
   * Update odometer
   */
  async updateOdometer(tenantId: string, id: string, odometer: number): Promise<Vehicle | null> {
    const vehicle = await this.findById(tenantId, id);
    if (!vehicle) return null;

    if (odometer < (vehicle.currentOdometer || 0)) {
      throw new Error('New odometer reading cannot be less than current');
    }

    vehicle.currentOdometer = odometer;
    vehicle.odometerUpdatedAt = new Date();
    return this.vehicleRepository.save(vehicle);
  }

  /**
   * Deactivate vehicle
   */
  async deactivate(tenantId: string, id: string): Promise<boolean> {
    const vehicle = await this.findById(tenantId, id);
    if (!vehicle) return false;

    vehicle.status = VehicleStatus.INACTIVE;
    await this.vehicleRepository.save(vehicle);
    return true;
  }

  /**
   * Get customer's vehicles
   */
  async findByCustomer(tenantId: string, customerId: string): Promise<Vehicle[]> {
    return this.vehicleRepository.find({
      where: { tenantId, customerId, status: VehicleStatus.ACTIVE },
      order: { createdAt: 'DESC' },
    });
  }

  /**
   * Get fleet's vehicles
   */
  async findByFleet(tenantId: string, fleetId: string): Promise<Vehicle[]> {
    return this.vehicleRepository.find({
      where: { tenantId, fleetId, status: VehicleStatus.ACTIVE },
      order: { createdAt: 'DESC' },
    });
  }

  /**
   * Get unique makes for filters
   */
  async getMakes(tenantId: string): Promise<string[]> {
    const result = await this.vehicleRepository
      .createQueryBuilder('vehicle')
      .select('DISTINCT vehicle.make', 'make')
      .where('vehicle.tenant_id = :tenantId', { tenantId })
      .orderBy('vehicle.make', 'ASC')
      .getRawMany();

    return result.map(r => r.make);
  }

  /**
   * Get models for a make
   */
  async getModels(tenantId: string, make: string): Promise<string[]> {
    const result = await this.vehicleRepository
      .createQueryBuilder('vehicle')
      .select('DISTINCT vehicle.model', 'model')
      .where('vehicle.tenant_id = :tenantId', { tenantId })
      .andWhere('vehicle.make = :make', { make })
      .orderBy('vehicle.model', 'ASC')
      .getRawMany();

    return result.map(r => r.model);
  }

  /**
   * Get vehicle statistics
   */
  async getStats(tenantId: string): Promise<{
    total: number;
    active: number;
    byVehicleType: Record<VehicleType, number>;
    byMake: { make: string; count: number }[];
  }> {
    const [total, active, vehicleTypeCounts, makeCounts] = await Promise.all([
      this.vehicleRepository.count({ where: { tenantId } }),
      this.vehicleRepository.count({ where: { tenantId, status: VehicleStatus.ACTIVE } }),
      this.vehicleRepository
        .createQueryBuilder('vehicle')
        .select('vehicle.vehicle_type', 'vehicleType')
        .addSelect('COUNT(*)', 'count')
        .where('vehicle.tenant_id = :tenantId', { tenantId })
        .groupBy('vehicle.vehicle_type')
        .getRawMany(),
      this.vehicleRepository
        .createQueryBuilder('vehicle')
        .select('vehicle.make', 'make')
        .addSelect('COUNT(*)', 'count')
        .where('vehicle.tenant_id = :tenantId', { tenantId })
        .groupBy('vehicle.make')
        .orderBy('count', 'DESC')
        .limit(10)
        .getRawMany(),
    ]);

    const byVehicleType: Record<VehicleType, number> = {
      [VehicleType.TRUCK]: 0,
      [VehicleType.TRAILER]: 0,
      [VehicleType.BUS]: 0,
      [VehicleType.PICKUP]: 0,
      [VehicleType.OTHER]: 0,
    };

    for (const row of vehicleTypeCounts) {
      if (row.vehicleType) {
        byVehicleType[row.vehicleType as VehicleType] = parseInt(row.count, 10);
      }
    }

    return {
      total,
      active,
      byVehicleType,
      byMake: makeCounts.map(r => ({ make: r.make, count: parseInt(r.count, 10) })),
    };
  }
}
