import {
  Injectable,
  ConflictException,
  NotFoundException,
  BadRequestException,
} from '@nestjs/common';
import { DestinationRepository } from './repositories/destination.repository';
import { CreateDestinationDto, UpdateDestinationDto } from './dto';
import { serviceMessages } from '../../common/constants/messages';

const MSG = serviceMessages('Destination');

@Injectable()
export class DestinationService {
  constructor(private readonly destRepo: DestinationRepository) {}

  async findAll(query?: { page?: number; limit?: number; search?: string }) {
    return this.destRepo.findPaginated({
      page: query?.page,
      limit: query?.limit,
      search: query?.search,
      searchColumns: ['name', 'short_code', 'country', 'city'],
      relations: ['currency'],
      order: { name: 'ASC' },
    });
  }

  async findAllForLookup() {
    return this.destRepo.find({
      select: ['id', 'name', 'short_code', 'country', 'city', 'services', 'currency_id'],
      relations: ['currency'],
      order: { name: 'ASC' } as any,
    });
  }

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

  async create(dto: CreateDestinationDto) {
    if (dto.short_code) {
      const existing = await this.destRepo.findByShortCode(dto.short_code);
      if (existing) throw new ConflictException(`Short code "${dto.short_code}" already exists`);
    }
    const dest = await this.destRepo.save({
      name: dto.name,
      short_code: dto.short_code,
      country: dto.country,
      city: dto.city,
      currency_id: dto.currency_id || null,
      timezone: dto.timezone || null,
      description: dto.description || null,
      image_url: dto.image_url || null,
      visa_required: dto.visa_required || false,
      tax_types: dto.tax_types || null,
      services: dto.services || null,
    });

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

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

    if (dto.short_code && dto.short_code !== dest.short_code) {
      const existing = await this.destRepo.findByShortCode(dto.short_code);
      if (existing && existing.id !== id) throw new ConflictException(`Short code "${dto.short_code}" already exists`);
    }
    const updateData: any = {};
    if (dto.name !== undefined) updateData.name = dto.name;
    if (dto.short_code !== undefined) updateData.short_code = dto.short_code;
    if (dto.country !== undefined) updateData.country = dto.country;
    if (dto.city !== undefined) updateData.city = dto.city;
    if (dto.currency_id !== undefined) updateData.currency_id = dto.currency_id;
    if (dto.timezone !== undefined) updateData.timezone = dto.timezone;
    if (dto.description !== undefined) updateData.description = dto.description;
    if (dto.image_url !== undefined) updateData.image_url = dto.image_url;
    if (dto.visa_required !== undefined) updateData.visa_required = dto.visa_required;
    if (dto.tax_types !== undefined) updateData.tax_types = dto.tax_types;
    if (dto.services !== undefined) updateData.services = dto.services;

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

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

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