package io.github.js0ny.ilp_coursework.controller;

import io.github.js0ny.ilp_coursework.data.external.Drone;
import io.github.js0ny.ilp_coursework.data.request.AttrQueryRequest;
import io.github.js0ny.ilp_coursework.data.request.MedDispatchRecRequest;
import io.github.js0ny.ilp_coursework.data.response.DeliveryPathResponse;
import io.github.js0ny.ilp_coursework.service.DroneAttrComparatorService;
import io.github.js0ny.ilp_coursework.service.DroneInfoService;
import io.github.js0ny.ilp_coursework.service.PathFinderService;

import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.List;

/**
 * Main Rest Controller for the ILP Coursework 2 application.
 *
 * <p>This class handles incoming HTTP requests for the API under {@code /api/v1} path (defined in
 * CW2) The business logic is delegated to {@link DroneInfoService}
 */
@RestController
@RequestMapping("/api/v1")
public class DroneController {

    private final DroneInfoService droneInfoService;
    private final DroneAttrComparatorService droneAttrComparatorService;
    private final PathFinderService pathFinderService;

    /**
     * Constructor of the {@code DroneController} with the business logic dependency {@code
     * DroneInfoService}
     *
     * <p>We handle the {@code baseUrl} here. Use a predefined URL if the environment variable
     * {@code ILP_ENDPOINT} is not given.
     *
     * @param droneService The service component that contains all business logic
     */
    public DroneController(
            DroneInfoService droneService,
            DroneAttrComparatorService droneAttrComparatorService,
            PathFinderService pathFinderService) {
        this.droneInfoService = droneService;
        this.droneAttrComparatorService = droneAttrComparatorService;
        this.pathFinderService = pathFinderService;
    }

    /**
     * Handles GET requests to retrieve an array of drones (identified by id) that has the
     * capability of cooling
     *
     * @param state The path variable that indicates the return should have or not have the
     *     capability
     * @return An array of drone id with cooling capability.
     */
    @GetMapping("/dronesWithCooling/{state}")
    public List<String> getDronesWithCoolingCapability(@PathVariable boolean state) {
        return droneInfoService.dronesWithCooling(state);
    }

    /**
     * Handles GET requests to retrieve the drone detail identified by id
     *
     * @param id The id of the drone to be queried.
     * @return 200 with {@link Drone}-style json if success, 404 if {@code id} not found, 400
     *     otherwise
     */
    @GetMapping("/droneDetails/{id}")
    public ResponseEntity<Drone> getDroneDetail(@PathVariable String id) {
        try {
            Drone drone = droneInfoService.droneDetail(id);
            return ResponseEntity.ok(drone);
        } catch (IllegalArgumentException ex) {
            return ResponseEntity.notFound().build();
        }
    }

    /**
     * Handles GET requests to retrieve an array of drone ids that {@code capability.attrName =
     * attrVal}
     *
     * @param attrName The name of the attribute to be queried
     * @param attrVal The value of the attribute to be queried
     * @return An array of drone id that matches the attribute name and value
     */
    @GetMapping("/queryAsPath/{attrName}/{attrVal}")
    public List<String> getIdByAttrMap(
            @PathVariable String attrName, @PathVariable String attrVal) {
        return droneAttrComparatorService.dronesWithAttribute(attrName, attrVal);
    }

    @PostMapping("/query")
    public List<String> getIdByAttrMapPost(@RequestBody AttrQueryRequest[] attrComparators) {
        return droneAttrComparatorService.dronesSatisfyingAttributes(attrComparators);
    }

    @PostMapping("/queryAvailableDrones")
    public List<String> queryAvailableDrones(@RequestBody MedDispatchRecRequest[] records) {
        return droneInfoService.dronesMatchesRequirements(records);
    }

    @PostMapping("/calcDeliveryPath")
    public DeliveryPathResponse calculateDeliveryPath(@RequestBody MedDispatchRecRequest[] record) {
        return pathFinderService.calculateDeliveryPath(record);
    }

    @PostMapping("/calcDeliveryPathAsGeoJson")
    public String calculateDeliveryPathAsGeoJson(@RequestBody MedDispatchRecRequest[] record) {
        return pathFinderService.calculateDeliveryPathAsGeoJson(record);
    }
}
