/**
 * @ai-summary Business logic for stations feature
 */

import { StationsRepository } from '../data/stations.repository';
import { googleMapsClient } from '../external/google-maps/google-maps.client';
import {
  StationSearchRequest,
  StationSearchResponse,
  StationMatchResponse,
  SavedStation,
  StationSavedMetadata,
  UpdateSavedStationBody
} from './stations.types';
import { logger } from '../../../core/logging/logger';

export class StationsService {
  constructor(private repository: StationsRepository) {}
  
  async searchNearbyStations(
    request: StationSearchRequest,
    userId: string
  ): Promise<StationSearchResponse> {
    logger.info('Searching for stations', { userId, ...request });
    
    // Search via Google Maps
    const stations = await googleMapsClient.searchNearbyStations(
      request.latitude,
      request.longitude,
      request.radius || 5000
    );

    // Fetch saved stations for prioritization and metadata
    const savedStations = await this.repository.getUserSavedStations(userId);
    const savedMap = new Map(savedStations.map(saved => [saved.placeId, saved]));
    
    // Cache stations for future reference
    for (const station of stations) {
      await this.repository.cacheStation(station);

      // Enrich station with saved metadata
      const saved = savedMap.get(station.placeId);
      if (saved) {
        station.isSaved = true;
        station.savedMetadata = this.mapSavedMetadata(saved);
      }
    }
    
    // Sort saved stations first, favorites next, then distance
    stations.sort((a, b) => {
      const aSaved = a.savedMetadata ? 1 : 0;
      const bSaved = b.savedMetadata ? 1 : 0;

      if (aSaved !== bSaved) {
        return bSaved - aSaved;
      }

      const aFavorite = a.savedMetadata?.isFavorite ? 1 : 0;
      const bFavorite = b.savedMetadata?.isFavorite ? 1 : 0;

      if (aFavorite !== bFavorite) {
        return bFavorite - aFavorite;
      }

      const aDistance = a.distance ?? Number.POSITIVE_INFINITY;
      const bDistance = b.distance ?? Number.POSITIVE_INFINITY;
      return aDistance - bDistance;
    });
    
    return {
      stations,
      searchLocation: {
        latitude: request.latitude,
        longitude: request.longitude
      },
      searchRadius: request.radius || 5000,
      timestamp: new Date().toISOString()
    };
  }
  
  async saveStation(
    placeId: string,
    userId: string,
    data?: {
      nickname?: string;
      notes?: string;
      isFavorite?: boolean;
      has93Octane?: boolean;
      has93OctaneEthanolFree?: boolean;
    }
  ) {
    // Get station details from cache
    const station = await this.repository.getCachedStation(placeId);
    
    if (!station) {
      throw new Error('Station not found. Please search for stations first.');
    }
    
    // Save to user's saved stations
    const saved = await this.repository.saveStation(userId, placeId, data);
    
    return {
      ...saved,
      station
    };
  }

  async updateSavedStation(
    placeId: string,
    userId: string,
    data: UpdateSavedStationBody
  ) {
    const updated = await this.repository.updateSavedStation(userId, placeId, data);

    if (!updated) {
      throw new Error('Saved station not found');
    }

    const station = await this.repository.getCachedStation(placeId);

    return {
      ...updated,
      station
    };
  }
  
  async getUserSavedStations(userId: string) {
    const savedStations = await this.repository.getUserSavedStations(userId);

    // Enrich with cached station data
    const enriched = await Promise.all(
      savedStations.map(async (saved: SavedStation) => {
        const station = await this.repository.getCachedStation(saved.stationId);

        // Flatten station data into top level to match frontend SavedStation type
        // Frontend expects SavedStation to extend Station
        return {
          ...saved,
          // Merge cached station data at top level (with fallbacks if cache miss)
          name: station?.name || saved.nickname || 'Saved Station',
          address: station?.address || '',
          latitude: station?.latitude || 0,
          longitude: station?.longitude || 0,
          rating: station?.rating,
          photoReference: station?.photoReference,
          priceRegular: station?.priceRegular,
          pricePremium: station?.pricePremium,
          priceDiesel: station?.priceDiesel,
          // Keep nested station for compatibility
          station
        };
      })
    );

    return enriched;
  }
  
  async matchStationFromReceipt(merchantName: string): Promise<StationMatchResponse> {
    const trimmed = merchantName.trim();
    if (!trimmed) {
      return { matched: false, station: null };
    }

    logger.info('Matching station from receipt merchant name', { merchantName: trimmed });

    const station = await googleMapsClient.searchStationByName(trimmed);

    if (station) {
      // Cache matched station for future reference (e.g. saveStation)
      await this.repository.cacheStation(station);
    }

    return {
      matched: station !== null,
      station,
    };
  }

  async removeSavedStation(placeId: string, userId: string) {
    const removed = await this.repository.deleteSavedStation(userId, placeId);
    
    if (!removed) {
      throw new Error('Saved station not found');
    }
  }

  private mapSavedMetadata(saved: SavedStation): StationSavedMetadata {
    return {
      nickname: saved.nickname,
      notes: saved.notes,
      isFavorite: saved.isFavorite,
      has93Octane: saved.has93Octane,
      has93OctaneEthanolFree: saved.has93OctaneEthanolFree
    };
  }
}
