import {
  Injectable,
  ConflictException,
  NotFoundException,
} from '@nestjs/common';
import { HotelRepository } from './repositories/hotel.repository';
import { CreateHotelDto, UpdateHotelDto } from './dto';
import { serviceMessages } from '../../common/constants/messages';

const MSG = serviceMessages('Hotel');

@Injectable()
export class HotelService {
  constructor(private readonly repo: HotelRepository) {}

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

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

  async findAllForLookup() {
    return this.repo.find({
      where: { is_active: true } as any,
      select: ['id', 'name', 'short_code', 'destination_id'],
      order: { name: '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: CreateHotelDto) {
    const existing = await this.repo.findByNameAndDestination(dto.name, dto.destination_id);
    if (existing) throw new ConflictException(MSG.ALREADY_EXISTS('name'));

    if (dto.short_code) {
      const codeExists = await this.repo.findByShortCode(dto.short_code);
      if (codeExists) throw new ConflictException(`Code "${dto.short_code}" already exists`);
    }

    const item = await this.repo.save({
      destination_id: dto.destination_id,
      short_code: dto.short_code,
      name: dto.name,
      address: dto.address,
      location: dto.location || null,
      gps_latitude: dto.gps_latitude || null,
      gps_longitude: dto.gps_longitude || null,
      pickup_gate: dto.pickup_gate || null,
      dropoff_gate: dto.dropoff_gate || null,
      contact_person: dto.contact_person,
      contact_phone: dto.contact_phone || null,
      special_instructions: dto.special_instructions || null,
      meeting_point: dto.meeting_point || null,
      is_active: dto.is_active ?? true,
    });

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

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

    if (dto.name || dto.destination_id) {
      const checkName = dto.name || item.name;
      const checkDest = dto.destination_id || item.destination_id;
      if (checkName !== item.name || checkDest !== item.destination_id) {
        const existing = await this.repo.findByNameAndDestination(checkName, checkDest);
        if (existing && existing.id !== id) throw new ConflictException(MSG.ALREADY_EXISTS('name'));
      }
    }

    if (dto.short_code && dto.short_code !== (item as any).short_code) {
      const codeExists = await this.repo.findByShortCode(dto.short_code);
      if (codeExists && codeExists.id !== id) throw new ConflictException(`Code "${dto.short_code}" already exists`);
    }

    const updateData: any = {};
    const fields = [
      'destination_id', 'short_code', 'name', 'address', 'location',
      'gps_latitude', 'gps_longitude', 'pickup_gate', 'dropoff_gate',
      'contact_person', 'contact_phone', 'special_instructions', 'meeting_point',
      '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 };
  }
}
