import {
  Injectable,
  ConflictException,
  NotFoundException,
  BadRequestException,
} from '@nestjs/common';
import { VehicleRepository } from './repositories/vehicle.repository';
import { CreateVehicleDto, UpdateVehicleDto } from './dto';
import { VehicleStatus } from '../../entities/vehicle.entity';
import { serviceMessages } from '../../common/constants/messages';

const MSG = serviceMessages('Vehicle');

@Injectable()
export class VehicleService {
  constructor(private readonly repo: VehicleRepository) {}

  async findAll(query?: { page?: number; limit?: number; search?: string }, filters?: { status?: string; type?: string; supplierId?: string; destinationId?: string }) {
    const where: any = {};
    if (filters?.status) where.status = filters.status;
    if (filters?.type) where.type = filters.type;
    if (filters?.supplierId) where.supplier_id = filters.supplierId;
    if (filters?.destinationId) where.destination_id = filters.destinationId;

    return this.repo.findPaginated({
      page: query?.page,
      limit: query?.limit,
      search: query?.search,
      searchColumns: ['vehicle_no', 'type', 'company', 'model'],
      relations: ['destination', 'supplier', 'assigned_driver'],
      order: { vehicle_no: 'ASC' },
      where,
    });
  }

  async findAllForLookup() {
    return this.repo.find({
      where: { is_active: true } as any,
      select: ['id', 'vehicle_no', 'type', 'capacity', 'capping', 'supplier_id', 'assigned_driver_id', 'destination_id'],
      order: { vehicle_no: 'ASC' } as any,
    });
  }

  async findById(id: string) {
    const item = await this.repo.findByIdWithRelations(id);
    if (!item) throw new NotFoundException(MSG.NOT_FOUND);
    return item;
  }

  async create(dto: CreateVehicleDto) {
    if (dto.vehicle_no) {
      const existing = await this.repo.findByVehicleNo(dto.vehicle_no);
      if (existing) throw new ConflictException(MSG.ALREADY_EXISTS('registration number'));
    }

    const item = await this.repo.save({
      destination_id: dto.destination_id || null,
      supplier_id: dto.supplier_id || null,
      assigned_driver_id: dto.assigned_driver_id || null,
      vehicle_no: dto.vehicle_no || null,
      type: dto.type || null,
      company: dto.company || null,
      model: dto.model || null,
      year: dto.year ?? null,
      capacity: dto.capacity ?? null,
      capping: dto.capping ?? null,
      fuel_type: dto.fuel_type || null,
      color: dto.color || null,
      insurance_expiry: dto.insurance_expiry || null,
      features: dto.features || null,
      status: dto.status || VehicleStatus.AVAILABLE,
      notes: dto.notes || null,
      is_active: dto.is_active ?? true,
    });

    // Auto-create transport pricing for this vehicle type on all routes in the destination
    try {
      const tenantId = (this.repo as any).getTenantId();
      const userId = (this.repo as any).cls?.get('user_id') || null;
      const manager = (this.repo as any).repo.manager;

      const dest = await manager.findOne('destinations', { where: { id: dto.destination_id } });
      const currencyId = dest?.currency_id;

      if (currencyId && dto.type) {
        // Find all active routes for this destination that don't have this vehicle type priced
        const routes = await manager.find('transport_services', {
          where: { destination_id: dto.destination_id, tenant_id: tenantId, is_deleted: false, is_active: true },
        });

        for (const route of routes) {
          const exists = await manager.findOne('transport_pricing', {
            where: { transport_service_id: route.id, cab_type: dto.type, currency_id: currencyId, tenant_id: tenantId, is_deleted: false },
          });
          if (!exists) {
            await manager.save('transport_pricing', {
              tenant_id: tenantId,
              destination_id: dto.destination_id,
              transport_service_id: route.id,
              category: route.category,
              cab_type: dto.type,
              currency_id: currencyId,
              created_by: userId,
              updated_by: userId,
            });
          }
        }
      }
    } catch { /* Don't fail vehicle creation */ }

    return { id: item.id, message: MSG.CREATED };
  }

  async update(id: string, dto: UpdateVehicleDto) {
    const item = await this.repo.findById(id);
    if (!item) throw new NotFoundException(MSG.NOT_FOUND);

    if (dto.vehicle_no && dto.vehicle_no !== item.vehicle_no) {
      const existing = await this.repo.findByVehicleNo(dto.vehicle_no);
      if (existing && existing.id !== id) throw new ConflictException(MSG.ALREADY_EXISTS('registration number'));
    }

    const updateData: any = {};
    const fields = [
      'destination_id', 'supplier_id', 'assigned_driver_id', 'vehicle_no',
      'type', 'company', 'model', 'year', 'capacity', 'capping', 'fuel_type',
      'color', 'insurance_expiry', 'features', 'status', 'notes', 'is_active',
    ];
    for (const field of fields) {
      if ((dto as any)[field] !== undefined) updateData[field] = (dto as any)[field];
    }

    await this.repo.update(id, updateData);
    return { id, message: MSG.UPDATED };
  }

  /**
   * Assign/unassign driver — inline action from list page.
   * Pass null to unassign.
   */
  async assignDriver(id: string, driverId: string | null) {
    const item = await this.repo.findById(id);
    if (!item) throw new NotFoundException(MSG.NOT_FOUND);

    await this.repo.update(id, {
      assigned_driver_id: driverId,
      status: driverId ? VehicleStatus.ASSIGNED : VehicleStatus.AVAILABLE,
    } as any);

    return { id, message: driverId ? 'Driver assigned successfully' : 'Driver unassigned successfully' };
  }

  async remove(id: string) {
    const item = await this.repo.findById(id);
    if (!item) throw new NotFoundException(MSG.NOT_FOUND);

    await this.repo.softDelete(id);
    return { message: MSG.DELETED };
  }
}
