import {
  Injectable,
  ConflictException,
  NotFoundException,
} from '@nestjs/common';
import { TransportServiceRepository } from './repositories/transport-service.repository';
import { CreateTransportServiceDto, UpdateTransportServiceDto } from './dto';
import { serviceMessages } from '../../common/constants/messages';

const MSG = serviceMessages('Transport service');

@Injectable()
export class TransportServiceService {
  constructor(
    private readonly repo: TransportServiceRepository,
  ) {}

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

    return this.repo.findPaginated({
      page: query?.page,
      limit: query?.limit,
      search: query?.search,
      searchColumns: ['short_code', 'from_city', 'to_city'],
      relations: ['destination'],
      order: { created_at: 'DESC' },
      where,
    });
  }

  async findAllForLookup() {
    return this.repo.find({
      where: { is_active: true } as any,
      select: ['id', 'short_code', 'category', 'from_city', 'to_city', 'destination_id', 'is_active'],
      order: { short_code: 'ASC' } as any,
    });
  }

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

  async create(dto: CreateTransportServiceDto) {
    const existing = await this.repo.findByShortCode(dto.short_code);
    if (existing) throw new ConflictException(MSG.ALREADY_EXISTS('short code'));

    const item = await this.repo.save({
      destination_id: dto.destination_id,
      short_code: dto.short_code,
      category: dto.category,
      from_city: dto.from_city,
      from_address: dto.from_address || null,
      from_gps_latitude: dto.from_gps_latitude || null,
      from_gps_longitude: dto.from_gps_longitude || null,
      to_city: dto.to_city,
      to_address: dto.to_address || null,
      to_gps_latitude: dto.to_gps_latitude || null,
      to_gps_longitude: dto.to_gps_longitude || null,
      return_from_city: dto.return_from_city || null,
      return_from_address: dto.return_from_address || null,
      return_from_gps_latitude: dto.return_from_gps_latitude || null,
      return_from_gps_longitude: dto.return_from_gps_longitude || null,
      return_to_city: dto.return_to_city || null,
      return_to_address: dto.return_to_address || null,
      return_to_gps_latitude: dto.return_to_gps_latitude || null,
      return_to_gps_longitude: dto.return_to_gps_longitude || null,
      distance_km: dto.distance_km ?? null,
      duration_mins: dto.duration_mins ?? null,
      description: dto.description || null,
      is_active: dto.is_active ?? true,
    });

    // Auto-create transport pricing for each vehicle type in this 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;

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

      // Get vehicle types from vehicles in this destination
      const vehicles = await manager.find('vehicles', { where: { destination_id: dto.destination_id, tenant_id: tenantId, is_deleted: false } });
      const vehicleTypeNames = [...new Set(vehicles.map((v: any) => v.type))];

      if (currencyId && vehicleTypeNames.length > 0) {
        for (const cabType of vehicleTypeNames) {
          await manager.save('transport_pricing', {
            tenant_id: tenantId,
            destination_id: dto.destination_id,
            transport_service_id: item.id,
            category: dto.category,
            cab_type: cabType,
            currency_id: currencyId,
            created_by: userId,
            updated_by: userId,
          });
        }
      }
    } catch { /* Don't fail route creation if pricing auto-create fails */ }

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

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

    if (dto.short_code && dto.short_code !== item.short_code) {
      const existing = await this.repo.findByShortCode(dto.short_code);
      if (existing) throw new ConflictException(MSG.ALREADY_EXISTS('short code'));
    }

    const updateData: any = {};
    const fields = [
      'destination_id', 'short_code', 'category',
      'from_city', 'from_address', 'from_gps_latitude', 'from_gps_longitude',
      'to_city', 'to_address', 'to_gps_latitude', 'to_gps_longitude',
      'return_from_city', 'return_from_address', 'return_from_gps_latitude', 'return_from_gps_longitude',
      'return_to_city', 'return_to_address', 'return_to_gps_latitude', 'return_to_gps_longitude',
      'distance_km', 'duration_mins', 'description', '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);

    // Sync category to transport pricing
    if (updateData.category) {
      const tenantId = (this.repo as any).getTenantId();
      await (this.repo as any).repo.manager.update('transport_pricing',
        { transport_service_id: id, tenant_id: tenantId, is_deleted: false },
        { category: updateData.category }
      );
    }

    return { id, message: MSG.UPDATED };
  }

  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 };
  }
}
