import {
  Injectable,
  ConflictException,
  NotFoundException,
} from '@nestjs/common';
import { DriverRepository } from './repositories/driver.repository';
import { CreateDriverDto, UpdateDriverDto } from './dto';
import { DriverStatus } from '../../entities/driver.entity';
import { serviceMessages } from '../../common/constants/messages';

const MSG = serviceMessages('Driver');

@Injectable()
export class DriverService {
  constructor(private readonly repo: DriverRepository) {}

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

    return this.repo.findPaginated({
      page: query?.page,
      limit: query?.limit,
      search: query?.search,
      searchColumns: ['name', 'phone', 'license_no'],
      relations: ['destination', 'supplier'],
      order: { name: 'ASC' },
      where,
    });
  }

  async findBySupplier(supplierId: string) {
    return this.repo.findBySupplier(supplierId);
  }

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

  async create(dto: CreateDriverDto) {
    const existing = await this.repo.findByLicenseNo(dto.license_no);
    if (existing) throw new ConflictException(MSG.ALREADY_EXISTS('license number'));

    const item = await this.repo.save({
      destination_id: dto.destination_id,
      supplier_id: dto.supplier_id,
      name: dto.name,
      phone: dto.phone,
      email: dto.email || null,
      alt_phone: dto.alt_phone || null,
      license_no: dto.license_no,
      license_expiry: dto.license_expiry || null,
      photo_url: dto.photo_url || null,
      address: dto.address || null,
      operational_hours: dto.operational_hours || null,
      status: dto.status || DriverStatus.AVAILABLE,
      notes: dto.notes || null,
      is_active: dto.is_active ?? true,
    });

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

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

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

    const updateData: any = {};
    const fields = [
      'destination_id', 'supplier_id', 'name', 'phone', 'email', 'alt_phone',
      'license_no', 'license_expiry', 'photo_url', 'address',
      'operational_hours', '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 };
  }

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