import { Body, Controller, Post } from '@nestjs/common';
import { ApiBearerAuth, ApiTags } from '@nestjs/swagger';
import { Throttle } from '@nestjs/throttler';
import { AlignPathDto } from './dto/align-path.dto';
import { DirectionsRouteDto } from './dto/directions-route.dto';
import { SnapPathDto } from './dto/snap-path.dto';
import { GoogleDirectionsClient } from './google-directions.client';
import { GoogleRoadsClient } from './google-roads.client';
import { PathAlignService } from './path-align.service';

/**
 * Stateless Google Directions / Roads proxy for Flutter GPS↔road merge.
 * Avoids browser CORS and keeps the Maps key server-side.
 */
@ApiTags('directions')
@ApiBearerAuth('access-token')
@Controller('directions')
export class DirectionsController {
  constructor(
    private readonly directions: GoogleDirectionsClient,
    private readonly roads: GoogleRoadsClient,
    private readonly pathAlign: PathAlignService,
  ) {}

  @Post('route')
  @Throttle({ default: { limit: 60, ttl: 60000 } })
  async route(@Body() body: DirectionsRouteDto) {
    const routes = await this.directions.fetchDrivingRoutes({
      origin: { lat: body.origin.lat, lng: body.origin.lng },
      destination: {
        lat: body.destination.lat,
        lng: body.destination.lng,
      },
      alternatives: body.alternatives !== false,
    });

    return {
      engine: 'google_directions',
      routes: routes.map((r) => ({
        routeIndex: r.routeIndex,
        distanceMeters: r.distanceMeters,
        distanceKm: r.distanceKm,
        durationSeconds: r.durationSeconds,
        durationMinutes: Math.max(1, Math.round(r.durationSeconds / 60)),
        polylineEncoded: r.polylineEncoded,
        points: r.polylinePoints,
      })),
    };
  }

  /**
   * Snap a GPS trail onto the road network (Google Roads API).
   */
  @Post('snap-path')
  @Throttle({ default: { limit: 30, ttl: 60000 } })
  async snapPath(@Body() body: SnapPathDto) {
    const path = body.points.map((p) => ({ lat: p.lat, lng: p.lng }));
    const interpolate = body.interpolate !== false;
    const snapped = await this.roads.snapToRoads(path, interpolate);
    return {
      engine: 'google_roads_snap',
      interpolate,
      points: snapped.map((p) => ({ lat: p.lat, lng: p.lng })),
    };
  }

  /**
   * Full merge: clean GPS → Directions kill-gaps → Snap-to-Roads.
   * Flutter should paint this path (not raw GPS chords).
   */
  @Post('align-path')
  @Throttle({ default: { limit: 20, ttl: 60000 } })
  async alignPath(@Body() body: AlignPathDto) {
    const input = body.points.map((p) => ({
      lat: p.lat,
      lng: p.lng,
      timestamp: p.timestamp ? this.parseTime(p.timestamp) : null,
    }));
    return this.pathAlign.align(input);
  }

  private parseTime(raw: string): Date | null {
    const n = Number(raw);
    if (Number.isFinite(n) && n > 1e11) {
      return new Date(n);
    }
    if (Number.isFinite(n) && n > 1e9) {
      return new Date(n * 1000);
    }
    const d = new Date(raw);
    return Number.isNaN(d.getTime()) ? null : d;
  }
}
