import { LocationRepository } from '../models/repositories/LocationRepository';
import { AppError } from '../utils/AppError';
import { generateUuid } from '../utils/uuid';
import { Location } from '../models/entities/Location.entity';

export class LocationService {
  constructor(private locationRepo = new LocationRepository()) {}

  async list(userId: string): Promise<Location[]> {
    return this.locationRepo.findByUserId(userId);
  }

  async create(
    userId: string,
    data: {
      name: string;
      address?: string | null;
      city?: string | null;
      description?: string | null;
    },
  ): Promise<Location> {
    const existing = await this.locationRepo.findByUserAndName(userId, data.name);
    if (existing) {
      throw new AppError('validation_error', 400, 'A location with this name already exists.');
    }

    return this.locationRepo.create({
      id: generateUuid(),
      userId,
      name: data.name.trim(),
      address: data.address ?? null,
      city: data.city ?? null,
      description: data.description ?? null,
      isActive: true,
    });
  }

  async update(
    userId: string,
    id: string,
    data: {
      name?: string;
      address?: string | null;
      city?: string | null;
      description?: string | null;
    },
  ): Promise<Location> {
    const location = await this.locationRepo.findById(id);
    if (!location || location.userId !== userId || !location.isActive) {
      throw new AppError('not_found', 404, 'Location not found.');
    }

    if (data.name && data.name.trim() !== location.name) {
      const existing = await this.locationRepo.findByUserAndName(userId, data.name.trim());
      if (existing && existing.id !== id) {
        throw new AppError('validation_error', 400, 'A location with this name already exists.');
      }
    }

    const patch: Partial<Location> = {};
    if (data.name !== undefined) patch.name = data.name.trim();
    if ('address' in data) patch.address = data.address ?? null;
    if ('city' in data) patch.city = data.city ?? null;
    if ('description' in data) patch.description = data.description ?? null;

    return this.locationRepo.update(id, patch);
  }

  async delete(userId: string, id: string): Promise<void> {
    const location = await this.locationRepo.findById(id);
    if (!location || location.userId !== userId || !location.isActive) {
      throw new AppError('not_found', 404, 'Location not found.');
    }
    await this.locationRepo.softDelete(id);
  }
}
