import { ConflictException, Injectable, NotFoundException } from '@nestjs/common';
import { PrismaService } from '../../common/prisma/prisma.service';
import { PlacesService } from '../places/places.service';
import type { CreateLocationFromPlaceInput, LocationTypeT } from '@vihar/shared';

@Injectable()
export class LocationsService {
  constructor(
    private readonly prisma: PrismaService,
    private readonly places: PlacesService,
  ) {}

  async search(
    cityId: number,
    query: { q?: string; type?: LocationTypeT; localityId?: number; limit: number },
  ) {
    return this.prisma.location.findMany({
      where: {
        cityId,
        isActive: true,
        ...(query.q
          ? {
              OR: [
                { name: { contains: query.q } },
                { formattedAddress: { contains: query.q } },
              ],
            }
          : {}),
        ...(query.type ? { locationType: query.type } : {}),
        ...(query.localityId ? { localityId: query.localityId } : {}),
      },
      take: query.limit,
      orderBy: { name: 'asc' },
      select: {
        locationId: true,
        name: true,
        locationType: true,
        formattedAddress: true,
        latitude: true,
        longitude: true,
        googlePlaceId: true,
        localityId: true,
      },
    });
  }

  async getById(cityId: number, locationId: number) {
    const loc = await this.prisma.location.findUnique({ where: { locationId } });
    if (!loc || loc.cityId !== cityId) throw new NotFoundException('Location not found');
    return loc;
  }

  async createFromPlaceId(
    cityId: number,
    createdBy: number,
    input: CreateLocationFromPlaceInput,
  ) {
    // Dedup: if this place_id already exists for the city, return it
    const existing = await this.prisma.location.findFirst({
      where: { cityId, googlePlaceId: input.placeId },
    });
    if (existing) {
      throw new ConflictException({
        message: 'Location already exists',
        existing,
      });
    }

    // Fetch fresh place details from Google. PlacesService also handles
    // session token termination (charged tier transition).
    const details = await this.places.fetchPlaceDetails(input.placeId, input.sessionToken);

    return this.prisma.location.create({
      data: {
        cityId,
        name: input.displayName ?? details.displayName,
        locationType: input.locationType,
        formattedAddress: details.formattedAddress,
        latitude: details.latitude,
        longitude: details.longitude,
        googlePlaceId: input.placeId,
        localityId: input.localityId ?? null,
        createdBy,
      },
    });
  }
}
