/**
 * PortSearchService
 *
 * Domain service for port search and autocomplete
 *
 * Business Rules:
 * - Fuzzy search on port name, city, and code
 * - Return top 10 results by default
 * - Support country filtering
 */

import { Port } from '../entities/port.entity';
import {
  GetPortsPort,
  PortSearchInput,
  PortSearchOutput,
  GetPortInput,
} from '@domain/ports/in/get-ports.port';
import { PortRepository } from '@domain/ports/out/port.repository';
import { PortNotFoundException } from '../exceptions/port-not-found.exception';

export class PortSearchService implements GetPortsPort {
  private static readonly DEFAULT_LIMIT = 10;

  constructor(private readonly portRepository: PortRepository) {}

  async search(input: PortSearchInput): Promise<PortSearchOutput> {
    const limit = input.limit || PortSearchService.DEFAULT_LIMIT;
    const query = input.query.trim();

    if (query.length === 0) {
      return {
        ports: [],
        totalMatches: 0,
      };
    }

    // Search using repository fuzzy search
    const ports = await this.portRepository.search(query, limit, input.countryFilter);

    return {
      ports,
      totalMatches: ports.length,
    };
  }

  async getByCode(input: GetPortInput): Promise<Port> {
    const port = await this.portRepository.findByCode(input.portCode);

    if (!port) {
      throw new PortNotFoundException(input.portCode);
    }

    return port;
  }

  async getByCodes(portCodes: string[]): Promise<Port[]> {
    const ports = await this.portRepository.findByCodes(portCodes);

    // Check if all ports were found
    const foundCodes = ports.map(p => p.code);
    const missingCodes = portCodes.filter(code => !foundCodes.includes(code));

    if (missingCodes.length > 0) {
      throw new PortNotFoundException(missingCodes[0]);
    }

    return ports;
  }
}
