package de.votian.services.controller;

import de.votian.services.dto.UserSessionDto;
import de.votian.services.security.AccessControlService;
import de.votian.services.service.GeoOperationsWorkspaceService;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.Authentication;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
@RequestMapping("/api/geo-operations")
public class GeoOperationsWorkspaceController {

    private final GeoOperationsWorkspaceService geoOperationsWorkspaceService;
    private final AccessControlService accessControlService;

    public GeoOperationsWorkspaceController(GeoOperationsWorkspaceService geoOperationsWorkspaceService,
                                           AccessControlService accessControlService) {
        this.geoOperationsWorkspaceService = geoOperationsWorkspaceService;
        this.accessControlService = accessControlService;
    }

    @GetMapping("/bootstrap")
    public ResponseEntity<GeoOperationsWorkspaceService.Bootstrap> bootstrap(@RequestParam Long hqId,
                                                                             Authentication authentication) {
        UserSessionDto user = accessControlService.sessionUser(authentication);
        if (!isWorkspaceAllowed(user, hqId)) {
            return ResponseEntity.status(HttpStatus.FORBIDDEN).build();
        }
        return ResponseEntity.ok(geoOperationsWorkspaceService.bootstrap(user, hqId));
    }

    @GetMapping("/map")
    public ResponseEntity<GeoOperationsWorkspaceService.MapDashboard> map(@RequestParam Long hqId,
                                                                          Authentication authentication) {
        UserSessionDto user = accessControlService.sessionUser(authentication);
        if (!isWorkspaceAllowed(user, hqId) || !accessControlService.canViewGlobalMap(user)) {
            return ResponseEntity.status(HttpStatus.FORBIDDEN).build();
        }
        return ResponseEntity.ok(geoOperationsWorkspaceService.loadMapDashboard(user, hqId));
    }

    @GetMapping("/addresses/search")
    public ResponseEntity<GeoOperationsWorkspaceService.AddressSearchResult> searchAddresses(@RequestParam Long hqId,
                                                                                             @RequestParam(required = false) String street,
                                                                                             @RequestParam(required = false) String zipcode,
                                                                                             @RequestParam(required = false) String city,
                                                                                             @RequestParam(required = false) String country,
                                                                                             Authentication authentication) {
        UserSessionDto user = accessControlService.sessionUser(authentication);
        if (!isWorkspaceAllowed(user, hqId) || !accessControlService.canManageAddressDirectory(user)) {
            return ResponseEntity.status(HttpStatus.FORBIDDEN).build();
        }
        return ResponseEntity.ok(geoOperationsWorkspaceService.searchAddresses(user, hqId, street, zipcode, city, country));
    }

    @PutMapping("/addresses/{id}")
    public ResponseEntity<GeoOperationsWorkspaceService.AddressRow> updateAddress(@PathVariable Long id,
                                                                                  @RequestBody AddressMutationRequest request,
                                                                                  Authentication authentication) {
        UserSessionDto user = accessControlService.sessionUser(authentication);
        if (request == null || !isWorkspaceAllowed(user, request.hqId) || !accessControlService.canManageAddressDirectory(user)) {
            return ResponseEntity.status(HttpStatus.FORBIDDEN).build();
        }
        return ResponseEntity.ok(geoOperationsWorkspaceService.updateAddress(
                user,
                request.hqId,
                id,
                request.street,
                request.zipcode,
                request.city,
                request.country
        ));
    }

    @PostMapping("/addresses/validated")
    public ResponseEntity<GeoOperationsWorkspaceService.ValidatedStreetRow> createValidatedStreet(@RequestBody AddressMutationRequest request,
                                                                                                  Authentication authentication) {
        UserSessionDto user = accessControlService.sessionUser(authentication);
        if (request == null || !isWorkspaceAllowed(user, request.hqId) || !accessControlService.canManageAddressDirectory(user)) {
            return ResponseEntity.status(HttpStatus.FORBIDDEN).build();
        }
        return ResponseEntity.ok(geoOperationsWorkspaceService.createValidatedStreet(
                user,
                request.hqId,
                request.street,
                request.zipcode,
                request.city,
                request.country
        ));
    }

    @DeleteMapping("/addresses/validated/{id}")
    public ResponseEntity<Void> deleteValidatedStreet(@PathVariable Long id,
                                                      @RequestParam Long hqId,
                                                      Authentication authentication) {
        UserSessionDto user = accessControlService.sessionUser(authentication);
        if (!isWorkspaceAllowed(user, hqId) || !accessControlService.canManageAddressDirectory(user)) {
            return ResponseEntity.status(HttpStatus.FORBIDDEN).build();
        }
        geoOperationsWorkspaceService.deleteValidatedStreet(user, hqId, id);
        return ResponseEntity.ok().build();
    }

    @GetMapping("/similarity")
    public ResponseEntity<List<GeoOperationsWorkspaceService.SimilarityResultRow>> similarity(@RequestParam Long hqId,
                                                                                               @RequestParam String type,
                                                                                               @RequestParam String phrase,
                                                                                               Authentication authentication) {
        UserSessionDto user = accessControlService.sessionUser(authentication);
        if (!isWorkspaceAllowed(user, hqId) || !accessControlService.canViewSimilaritySearch(user)) {
            return ResponseEntity.status(HttpStatus.FORBIDDEN).build();
        }
        return ResponseEntity.ok(geoOperationsWorkspaceService.searchSimilarity(user, hqId, type, phrase));
    }

    @GetMapping("/travel-times")
    public ResponseEntity<GeoOperationsWorkspaceService.TravelTimeResult> travelTimes(@RequestParam Long hqId,
                                                                                       @RequestParam String mode,
                                                                                       @RequestParam String zipcodeFrom,
                                                                                       @RequestParam String zipcodeTo,
                                                                                       Authentication authentication) {
        UserSessionDto user = accessControlService.sessionUser(authentication);
        if (!isWorkspaceAllowed(user, hqId) || !accessControlService.canManageTravelTimes(user)) {
            return ResponseEntity.status(HttpStatus.FORBIDDEN).build();
        }
        return ResponseEntity.ok(geoOperationsWorkspaceService.loadTravelTimes(user, hqId, mode, zipcodeFrom, zipcodeTo));
    }

    @PutMapping("/travel-times")
    public ResponseEntity<GeoOperationsWorkspaceService.SaveResult> saveTravelTimes(@RequestBody TravelTimeSaveRequest request,
                                                                                    Authentication authentication) {
        UserSessionDto user = accessControlService.sessionUser(authentication);
        if (request == null || !isWorkspaceAllowed(user, request.hqId) || !accessControlService.canManageTravelTimes(user)) {
            return ResponseEntity.status(HttpStatus.FORBIDDEN).build();
        }
        return ResponseEntity.ok(geoOperationsWorkspaceService.saveTravelTimes(
                user,
                request.hqId,
                request.mode,
                request.rows
        ));
    }

    private boolean isWorkspaceAllowed(UserSessionDto user, Long hqId) {
        return accessControlService.canViewGeoOperations(user)
                && accessControlService.canAccessHeadquarters(user, hqId);
    }

    @ExceptionHandler(IllegalArgumentException.class)
    public ResponseEntity<String> handleIllegalArgument(IllegalArgumentException exception) {
        return ResponseEntity.badRequest().body(exception.getMessage());
    }

    public static class AddressMutationRequest {
        public Long hqId;
        public String street;
        public String zipcode;
        public String city;
        public String country;
    }

    public static class TravelTimeSaveRequest {
        public Long hqId;
        public String mode;
        public List<GeoOperationsWorkspaceService.TravelTimeUpdate> rows;
    }
}
