OutdoorDirectionsController.java

package com.soen390.backend.controller;

import com.soen390.backend.enums.BuildingLocation;
import com.soen390.backend.enums.Campus;
import com.soen390.backend.exception.GoogleMapsDirectionEmptyException;
import com.soen390.backend.exception.GoogleMapsDirectionsApiException;
import com.soen390.backend.object.OutdoorDirectionResponse;
import com.soen390.backend.enums.TransportMode;
import com.soen390.backend.service.GoogleMapsService;
import com.soen390.backend.service.ShuttleOutdoorDirectionsService;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.server.ResponseStatusException;

import java.util.Locale;
import java.util.Map;

@RestController
@RequestMapping("/api/directions/outdoor")
public class OutdoorDirectionsController {
    private static final String ERROR_KEY = "error";
    private final GoogleMapsService mapsService;

    private final ShuttleOutdoorDirectionsService shuttleOutdoorDirectionsService;

    public OutdoorDirectionsController(GoogleMapsService mapsService, ShuttleOutdoorDirectionsService shuttleOutdoorDirectionsService) {
        this.mapsService = mapsService;
        this.shuttleOutdoorDirectionsService = shuttleOutdoorDirectionsService;
    }


    @GetMapping
    public ResponseEntity<Object> getDirections(
            @RequestParam String origin,
            @RequestParam String destination,
            @RequestParam String transportMode,
            @RequestParam(required = false) String originBuildingId,
            @RequestParam(required = false) String destinationBuildingId) {
        TransportMode normalizedTransportMode;
        try {
            normalizedTransportMode = TransportMode.valueOf(transportMode.toUpperCase(Locale.ROOT));
        } catch (IllegalArgumentException ex) {
            throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Invalid transportMode: " + transportMode, ex);
        }

        String resolvedOrigin = resolveEndpoint(origin, originBuildingId);
        String resolvedDestination = resolveEndpoint(destination, destinationBuildingId);

        try {
            OutdoorDirectionResponse response =
                    mapsService.getDirections(resolvedOrigin, resolvedDestination, normalizedTransportMode);
            return ResponseEntity.ok(response);
        } catch (GoogleMapsDirectionEmptyException e) {
            return ResponseEntity.status(HttpStatus.NOT_FOUND).body(Map.of(ERROR_KEY, e.getMessage()));
        } catch (GoogleMapsDirectionsApiException e) {
            return ResponseEntity.status(HttpStatus.BAD_GATEWAY).body(Map.of(ERROR_KEY, e.getMessage()));
        }
    }

    @GetMapping("/shuttle")
    public ResponseEntity<Object> getDirectionsWithShuttle(
            @RequestParam String origin,
            @RequestParam String destination,
            @RequestParam Campus destinationShuttle,
            @RequestParam(required = false) String originBuildingId,
            @RequestParam(required = false) String destinationBuildingId) {
        String resolvedOrigin = resolveEndpoint(origin, originBuildingId);
        String resolvedDestination = resolveEndpoint(destination, destinationBuildingId);

        try {
            OutdoorDirectionResponse response =
                    shuttleOutdoorDirectionsService.getShuttleOutdoorDirections(
                            resolvedOrigin, resolvedDestination, destinationShuttle);
            return ResponseEntity.ok(response);
        } catch (GoogleMapsDirectionEmptyException e) {
            return ResponseEntity.status(HttpStatus.NOT_FOUND).body(Map.of(ERROR_KEY, e.getMessage()));
        } catch (GoogleMapsDirectionsApiException e) {
            return ResponseEntity.status(HttpStatus.BAD_GATEWAY).body(Map.of(ERROR_KEY, e.getMessage()));
        }
    }

    private String resolveEndpoint(String fallbackValue, String buildingId) {
        if (buildingId == null || buildingId.isBlank()) {
            return fallbackValue;
        }
        return BuildingLocation.fromId(buildingId).getDirectionsTarget();
    }
}