package de.avatic.lcc.controller.calculation;


import de.avatic.lcc.dto.calculation.CalculationStatus;
import de.avatic.lcc.dto.calculation.DestinationDTO;
import de.avatic.lcc.dto.calculation.PremiseDTO;
import de.avatic.lcc.dto.calculation.ResolvePremiseDTO;
import de.avatic.lcc.dto.calculation.create.CreatePremiseDTO;
import de.avatic.lcc.dto.calculation.create.PremiseSearchResultDTO;
import de.avatic.lcc.dto.calculation.edit.PremiseDetailDTO;
import de.avatic.lcc.dto.calculation.edit.destination.DestinationCreateDTO;
import de.avatic.lcc.dto.calculation.edit.destination.DestinationMassUpdateDTO;
import de.avatic.lcc.dto.calculation.edit.destination.DestinationSetDTO;
import de.avatic.lcc.dto.calculation.edit.destination.DestinationUpdateDTO;
import de.avatic.lcc.dto.calculation.edit.masterData.MaterialUpdateDTO;
import de.avatic.lcc.dto.calculation.edit.masterData.PackagingUpdateDTO;
import de.avatic.lcc.dto.calculation.edit.masterData.PriceUpdateDTO;
import de.avatic.lcc.service.access.DestinationService;
import de.avatic.lcc.service.access.PremisesService;
import de.avatic.lcc.service.calculation.PremiseCreationService;
import de.avatic.lcc.service.calculation.PremiseSearchStringAnalyzerService;
import de.avatic.lcc.util.exception.badrequest.InvalidArgumentException;
import de.avatic.lcc.util.exception.base.BadRequestException;
import jakarta.validation.Valid;
import jakarta.validation.constraints.Min;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.util.Collections;
import java.util.List;
import java.util.Map;

@RestController
@RequestMapping("/api/calculation")
@Validated
public class PremiseController {

    private static final Logger log = LoggerFactory.getLogger(PremiseController.class);

    private final PremiseSearchStringAnalyzerService premiseSearchStringAnalyzerService;
    private final PremisesService premisesServices;
    private final PremiseCreationService premiseCreationService;
    private final DestinationService destinationService;

    public PremiseController(PremiseSearchStringAnalyzerService premiseSearchStringAnalyzerService, PremisesService premisesServices, PremiseCreationService premiseCreationService, DestinationService destinationService) {
        this.premiseSearchStringAnalyzerService = premiseSearchStringAnalyzerService;
        this.premisesServices = premisesServices;
        this.premiseCreationService = premiseCreationService;
        this.destinationService = destinationService;
    }

    @GetMapping({"/view", "/view/"})
    @PreAuthorize("hasAnyRole('SUPER', 'CALCULATION')")
    public ResponseEntity<List<PremiseDTO>> listPremises(@RequestParam(required = false) String filter,
                                                         @RequestParam(defaultValue = "20") @Min(1) int limit,
                                                         @RequestParam(defaultValue = "1") @Min(1) int page,
                                                         @RequestParam(name = "user", required = false) Integer userId,
                                                         @RequestParam(required = false) Boolean draft,
                                                         @RequestParam(required = false) Boolean archived,
                                                         @RequestParam(required = false) Boolean done) {

        var premises = premisesServices.listPremises(filter, page, limit, userId, draft, archived, done);

        return ResponseEntity.ok()
                .header("X-Total-Count", String.valueOf(premises.getTotalElements()))
                .header("X-Page-Count", String.valueOf(premises.getTotalPages()))
                .header("X-Current-Page", String.valueOf(page))
                .body(premises.toList());
    }

    @GetMapping({"/search", "/search/"})
    @PreAuthorize("hasAnyRole('SUPER', 'CALCULATION')")
    public ResponseEntity<PremiseSearchResultDTO> findMaterialsAndSuppliers(@RequestParam String search) {

        try {
//            String decodedValue = URLDecoder.decode(search, StandardCharsets.UTF_8);
            return ResponseEntity.ok(premiseSearchStringAnalyzerService.findMaterialAndSuppliers(search));
        } catch (Exception e) {
            throw new BadRequestException("Bad string encoding", "Unable to decode request", e);
        }
    }

    @PostMapping({"/create", "/create/"})
    @PreAuthorize("hasAnyRole('SUPER', 'CALCULATION')")
    public ResponseEntity<List<PremiseDetailDTO>> createPremises(@RequestBody @Valid CreatePremiseDTO dto) {

        if ((dto.getSupplierIds() == null || dto.getSupplierIds().isEmpty()) && (dto.getUserSupplierIds() == null || dto.getUserSupplierIds().isEmpty())) {
            throw new InvalidArgumentException("Either suppliers or userSuppliers must be provided. Suppliers: "
                    + dto.getSupplierIds() + ", userSuppliers: " + dto.getUserSupplierIds() + ".");
        }

        return ResponseEntity.ok(premiseCreationService.createPremises(
                dto.getMaterialIds(),
                dto.getSupplierIds() == null ? Collections.emptyList() : dto.getSupplierIds(),
                dto.getUserSupplierIds() == null ? Collections.emptyList() : dto.getUserSupplierIds(),
                dto.createEmpty()));
    }

    @GetMapping({"/resolve", "/resolve/"})
    @PreAuthorize("hasAnyRole('SUPER', 'CALCULATION')")
    public ResponseEntity<ResolvePremiseDTO> resolvePremiseStatus(@RequestParam List<Integer> premissIds) {
        return ResponseEntity.ok(premisesServices.resolveStatus(premissIds));
    }

    @GetMapping({"/duplicate", "/duplicate/"})
    @PreAuthorize("hasAnyRole('SUPER', 'CALCULATION')")
    public ResponseEntity<List<Integer>> duplicate(@RequestParam List<Integer> premissIds) {
        return ResponseEntity.ok(premisesServices.duplicate(premissIds));
    }

    @PostMapping({"/delete", "/delete/"})
    @PreAuthorize("hasAnyRole('SUPER', 'CALCULATION')")
    public ResponseEntity<Void> deletePremises(@RequestParam List<Integer> premissIds) {
        premisesServices.delete(premissIds);
        return ResponseEntity.ok().build();
    }

    @PostMapping({"/archive", "/archive/"})
    @PreAuthorize("hasAnyRole('SUPER', 'CALCULATION')")
    public ResponseEntity<Void> archivePremises(@RequestParam List<Integer> premissIds) {
        premisesServices.archive(premissIds);
        return ResponseEntity.ok().build();
    }

    @GetMapping({"/edit", "/edit/"})
    @PreAuthorize("hasAnyRole('SUPER', 'CALCULATION')")
    public ResponseEntity<List<PremiseDetailDTO>> getPremises(@RequestParam List<Integer> premissIds) {
        var premisses = premisesServices.getPremises(premissIds);
        return ResponseEntity.ok(premisses);
    }

    @PutMapping({"/start", "/start/"})
    @PreAuthorize("hasAnyRole('SUPER', 'CALCULATION')")
    public ResponseEntity<Void> startCalculation(@RequestBody List<Integer> premiseIds) {
        premisesServices.startCalculation(premiseIds);
        return ResponseEntity.ok().build();
    }

    /**
     * Retrieves the current status of a specific calculation processing operation.
     *
     * @param id The unique identifier of the operation (processing_id) to check its status.
     * @return A ResponseEntity with the bulk processing status payload.
     */
    @GetMapping({"/status/{processing_id}", "/status/{processing_id}/"})
    @PreAuthorize("hasAnyRole('SUPER', 'CALCULATION')")
    public ResponseEntity<CalculationStatus> getCalculationStatus(@PathVariable("processing_id") Integer id) {
        return ResponseEntity.ok(premisesServices.getCalculationStatus(id));
    }


    @PostMapping({"/packaging", "/packaging/"})
    @PreAuthorize("hasAnyRole('SUPER', 'CALCULATION')")
    public ResponseEntity<Void> updatePackaging(@RequestBody PackagingUpdateDTO packagingDTO) {
        premisesServices.updatePackaging(packagingDTO);
        return ResponseEntity.ok().build();
    }

    @PostMapping({"/material", "/material/"})
    @PreAuthorize("hasAnyRole('SUPER', 'CALCULATION')")
    public ResponseEntity<Void> updateMaterial(@RequestBody @Valid MaterialUpdateDTO materialUpdateDTO) {
        premisesServices.updateMaterial(materialUpdateDTO);
        return ResponseEntity.ok().build();
    }

    @PostMapping({"/price", "/price/"})
    @PreAuthorize("hasAnyRole('SUPER', 'CALCULATION')")
    public ResponseEntity<Void> updatePrice(@RequestBody @Valid PriceUpdateDTO priceUpdateDTO) {
        premisesServices.updatePrice(priceUpdateDTO);
        return ResponseEntity.ok().build();
    }

    @PostMapping({"/destination", "/destination/"})
    @PreAuthorize("hasAnyRole('SUPER', 'CALCULATION')")
    public ResponseEntity<Map<Integer, List<DestinationDTO>>> createDestination(@RequestBody @Valid DestinationCreateDTO destinationCreateDTO) {
        return ResponseEntity.ok(destinationService.massSetDestinations(destinationCreateDTO));
    }

    @PutMapping({"/destination", "/destination/"})
    @PreAuthorize("hasAnyRole('SUPER', 'CALCULATION')")
    public ResponseEntity<Map<Integer, List<DestinationDTO>>> setDestination(@RequestBody DestinationSetDTO destinationSetDTO) {
        return ResponseEntity.ok(destinationService.massSetDestinationProperties(destinationSetDTO));
    }

    @GetMapping({"/destination/{id}", "/destination/{id}/"})
    @PreAuthorize("hasAnyRole('SUPER', 'CALCULATION')")
    public ResponseEntity<DestinationDTO> getDestination(@PathVariable Integer id) {
        return ResponseEntity.ok(destinationService.getDestination(id));
    }

    @PutMapping({"/destination/{id}", "/destination/{id}/"})
    @PreAuthorize("hasAnyRole('SUPER', 'CALCULATION')")
    public ResponseEntity<Void> updateDestination(@PathVariable @Min(1) Integer id, @RequestBody @Valid DestinationUpdateDTO destinationUpdateDTO) {
        log.info("Updating destination {}", destinationUpdateDTO);
        destinationService.updateDestination(id, destinationUpdateDTO);
        return ResponseEntity.ok().build();
    }

    @PutMapping({"/destination/all", "/destination/all/"})
    @PreAuthorize("hasAnyRole('SUPER', 'CALCULATION')")
    public ResponseEntity<Void> updateAllDestination(@RequestBody @Valid DestinationMassUpdateDTO destinationUpdateDTO) {
        destinationUpdateDTO.getDestinations().forEach(destinationService::updateDestination);
        return ResponseEntity.ok().build();
    }

    @DeleteMapping({"/destination/{id}", "/destination/{id}/"})
    @PreAuthorize("hasAnyRole('SUPER', 'CALCULATION')")
    public ResponseEntity<Void> deleteDestination(@PathVariable Integer id) {
        destinationService.deleteDestinationById(id, false);
        return ResponseEntity.ok().build();
    }



}
