package de.votian.services.controller;

import de.votian.services.dto.ServicePriceRowDto;
import de.votian.services.dto.UserSessionDto;
import de.votian.services.entity.ServiceEntity;
import de.votian.services.entity.ServiceHistory;
import de.votian.services.entity.ServiceType;
import de.votian.services.repository.ServiceEntityRepository;
import de.votian.services.repository.ServiceHistoryRepository;
import de.votian.services.repository.ServiceTypeRepository;
import de.votian.services.security.AccessControlService;
import de.votian.services.service.ViewDataService;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.Authentication;
import org.springframework.web.bind.annotation.*;

import java.time.LocalDate;
import java.time.LocalTime;
import java.util.List;
import java.util.Objects;

@RestController
@RequestMapping("/api/services")
public class ServiceController {

    private final ServiceEntityRepository serviceRepository;
    private final ServiceTypeRepository serviceTypeRepository;
    private final ServiceHistoryRepository serviceHistoryRepository;
    private final ViewDataService viewDataService;
    private final AccessControlService accessControlService;

    public ServiceController(ServiceEntityRepository serviceRepository,
                             ServiceTypeRepository serviceTypeRepository,
                             ServiceHistoryRepository serviceHistoryRepository,
                             ViewDataService viewDataService,
                             AccessControlService accessControlService) {
        this.serviceRepository = serviceRepository;
        this.serviceTypeRepository = serviceTypeRepository;
        this.serviceHistoryRepository = serviceHistoryRepository;
        this.viewDataService = viewDataService;
        this.accessControlService = accessControlService;
    }

    @GetMapping("/hq/{hqId}")
    public ResponseEntity<List<ServiceEntity>> findByHq(@PathVariable Long hqId, Authentication authentication) {
        UserSessionDto user = accessControlService.sessionUser(authentication);
        if (!accessControlService.canManagePricing(user) || !accessControlService.canAccessHeadquarters(user, hqId)) {
            return ResponseEntity.status(HttpStatus.FORBIDDEN).build();
        }
        return ResponseEntity.ok(serviceRepository.findByHeadquartersId(hqId));
    }

    @GetMapping("/types/hq/{hqId}")
    public ResponseEntity<List<ServiceType>> findTypesByHq(@PathVariable Long hqId, Authentication authentication) {
        UserSessionDto user = accessControlService.sessionUser(authentication);
        if (!accessControlService.canManagePricing(user) || !accessControlService.canAccessHeadquarters(user, hqId)) {
            return ResponseEntity.status(HttpStatus.FORBIDDEN).build();
        }
        return ResponseEntity.ok(serviceTypeRepository.findByHeadquartersId(hqId));
    }

    @GetMapping("/price")
    public ResponseEntity<ServiceHistory> getPrice(@RequestParam Long serviceId,
                                                   @RequestParam Long customerId,
                                                   @RequestParam Long hqId,
                                                   @RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate date,
                                                   Authentication authentication) {
        UserSessionDto user = accessControlService.sessionUser(authentication);
        if (!accessControlService.canManagePricing(user) || !accessControlService.canAccessHeadquarters(user, hqId)) {
            return ResponseEntity.status(HttpStatus.FORBIDDEN).build();
        }
        return serviceHistoryRepository.findLatestPrice(serviceId, customerId, hqId, date.atTime(LocalTime.MAX))
                .map(ResponseEntity::ok)
                .orElse(ResponseEntity.notFound().build());
    }

    @GetMapping("/prices")
    public ResponseEntity<List<ServicePriceRowDto>> getPrices(@RequestParam Long hqId,
                                                              @RequestParam(required = false) Long customerId,
                                                              Authentication authentication) {
        UserSessionDto user = accessControlService.sessionUser(authentication);
        if (!accessControlService.canManagePricing(user) || !accessControlService.canAccessHeadquarters(user, hqId)) {
            return ResponseEntity.status(HttpStatus.FORBIDDEN).build();
        }
        return ResponseEntity.ok(viewDataService.findServicePrices(hqId, customerId));
    }

    @PostMapping("/entity")
    public ResponseEntity<ServiceEntity> createService(@RequestBody ServiceEntity serviceEntity, Authentication authentication) {
        UserSessionDto user = accessControlService.sessionUser(authentication);
        if (serviceEntity == null
                || !accessControlService.canManagePricing(user)
                || !accessControlService.canAccessHeadquarters(user, serviceEntity.getHeadquartersId())) {
            return ResponseEntity.status(HttpStatus.FORBIDDEN).build();
        }
        return ResponseEntity.ok(serviceRepository.save(serviceEntity));
    }

    @PutMapping("/entity/{id}")
    public ResponseEntity<ServiceEntity> updateService(@PathVariable Long id,
                                                       @RequestBody ServiceEntity updates,
                                                       Authentication authentication) {
        UserSessionDto user = accessControlService.sessionUser(authentication);
        return serviceRepository.findById(Objects.requireNonNull(id))
                .map(existing -> {
                    if (!accessControlService.canManagePricing(user)
                            || !accessControlService.canAccessHeadquarters(user, existing.getHeadquartersId())) {
                        return ResponseEntity.status(HttpStatus.FORBIDDEN).<ServiceEntity>build();
                    }
                    if (updates.getName() != null) {
                        existing.setName(updates.getName());
                    }
                    if (updates.getMode() != null) {
                        existing.setMode(updates.getMode());
                    }
                    if (updates.getServiceTypeId() != null) {
                        existing.setServiceTypeId(updates.getServiceTypeId());
                    }
                    if (updates.getHeadquartersId() != null) {
                        existing.setHeadquartersId(updates.getHeadquartersId());
                    }
                    if (updates.getCustomerId() != null) {
                        existing.setCustomerId(updates.getCustomerId());
                    }
                    return ResponseEntity.ok(serviceRepository.save(existing));
                })
                .orElse(ResponseEntity.notFound().build());
    }

    @PostMapping("/types")
    public ResponseEntity<ServiceType> createServiceType(@RequestBody ServiceType serviceType, Authentication authentication) {
        UserSessionDto user = accessControlService.sessionUser(authentication);
        if (serviceType == null
                || !accessControlService.canManagePricing(user)
                || !accessControlService.canAccessHeadquarters(user, serviceType.getHeadquartersId())) {
            return ResponseEntity.status(HttpStatus.FORBIDDEN).build();
        }
        return ResponseEntity.ok(serviceTypeRepository.save(serviceType));
    }

    @PutMapping("/types/{id}")
    public ResponseEntity<ServiceType> updateServiceType(@PathVariable Long id,
                                                         @RequestBody ServiceType updates,
                                                         Authentication authentication) {
        UserSessionDto user = accessControlService.sessionUser(authentication);
        return serviceTypeRepository.findById(Objects.requireNonNull(id))
                .map(existing -> {
                    if (!accessControlService.canManagePricing(user)
                            || !accessControlService.canAccessHeadquarters(user, existing.getHeadquartersId())) {
                        return ResponseEntity.status(HttpStatus.FORBIDDEN).<ServiceType>build();
                    }
                    if (updates.getName() != null) {
                        existing.setName(updates.getName());
                    }
                    if (updates.getMode() != null) {
                        existing.setMode(updates.getMode());
                    }
                    if (updates.getHeadquartersId() != null) {
                        existing.setHeadquartersId(updates.getHeadquartersId());
                    }
                    if (updates.getCustomerId() != null) {
                        existing.setCustomerId(updates.getCustomerId());
                    }
                    return ResponseEntity.ok(serviceTypeRepository.save(existing));
                })
                .orElse(ResponseEntity.notFound().build());
    }

    @PostMapping("/history")
    public ResponseEntity<ServiceHistory> savePriceHistory(@RequestBody ServiceHistory history, Authentication authentication) {
        UserSessionDto user = accessControlService.sessionUser(authentication);
        if (history == null
                || !accessControlService.canManagePricing(user)
                || !accessControlService.canAccessHeadquarters(user, history.getHeadquartersId())) {
            return ResponseEntity.status(HttpStatus.FORBIDDEN).build();
        }
        return ResponseEntity.ok(serviceHistoryRepository.save(history));
    }
}
