package de.votian.services.controller;

import de.votian.services.dto.UserSessionDto;
import de.votian.services.entity.CostCenter;
import de.votian.services.entity.CostCenterAddress;
import de.votian.services.repository.CostCenterAddressRepository;
import de.votian.services.repository.CostCenterRepository;
import de.votian.services.security.AccessControlService;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.lang.NonNull;
import org.springframework.security.core.Authentication;
import org.springframework.web.bind.annotation.*;

import java.util.List;
import java.util.Objects;

@RestController
@RequestMapping("/api/costcenters")
public class CostCenterController {

    private final CostCenterRepository costCenterRepository;
    private final CostCenterAddressRepository costCenterAddressRepository;
    private final AccessControlService accessControlService;

    public CostCenterController(CostCenterRepository costCenterRepository,
                                CostCenterAddressRepository costCenterAddressRepository,
                                AccessControlService accessControlService) {
        this.costCenterRepository = costCenterRepository;
        this.costCenterAddressRepository = costCenterAddressRepository;
        this.accessControlService = accessControlService;
    }

    @GetMapping("/{id}")
    public ResponseEntity<CostCenter> findById(@PathVariable @NonNull Long id, Authentication authentication) {
        UserSessionDto user = accessControlService.sessionUser(authentication);
        return costCenterRepository.findById(id)
                .map(costCenter -> accessControlService.canAccessCostCenter(user, costCenter)
                        ? ResponseEntity.ok(costCenter)
                        : ResponseEntity.status(HttpStatus.FORBIDDEN).<CostCenter>build())
                .orElse(ResponseEntity.notFound().build());
    }

    @GetMapping("/customer/{customerId}")
    public ResponseEntity<List<CostCenter>> findByCustomer(@PathVariable Long customerId, Authentication authentication) {
        UserSessionDto user = accessControlService.sessionUser(authentication);
        if (!accessControlService.canAccessCustomer(user, customerId) || !accessControlService.canViewCostCenters(user)) {
            return ResponseEntity.status(HttpStatus.FORBIDDEN).build();
        }
        return ResponseEntity.ok(costCenterRepository.findByCustomerId(customerId).stream()
                .filter(costCenter -> accessControlService.canAccessCostCenter(user, costCenter))
                .toList());
    }

    @GetMapping("/customer/{customerId}/visible")
    public ResponseEntity<List<CostCenter>> findVisibleByCustomer(@PathVariable Long customerId, Authentication authentication) {
        UserSessionDto user = accessControlService.sessionUser(authentication);
        if (!accessControlService.canAccessCustomer(user, customerId) || !accessControlService.canViewCostCenters(user)) {
            return ResponseEntity.status(HttpStatus.FORBIDDEN).build();
        }
        return ResponseEntity.ok(costCenterRepository.findVisibleByCustomerId(customerId).stream()
                .filter(costCenter -> accessControlService.canAccessCostCenter(user, costCenter))
                .toList());
    }

    @PostMapping
    public ResponseEntity<CostCenter> save(@RequestBody CostCenter costCenter, Authentication authentication) {
        UserSessionDto user = accessControlService.sessionUser(authentication);
        if (costCenter == null
                || !accessControlService.canAccessCustomer(user, costCenter.getCustomerId())
                || !accessControlService.canManageCostCenters(user)) {
            return ResponseEntity.status(HttpStatus.FORBIDDEN).build();
        }
        return ResponseEntity.ok(costCenterRepository.save(costCenter));
    }

    @PutMapping("/{id}")
    public ResponseEntity<CostCenter> update(@PathVariable @NonNull Long id,
                                             @RequestBody CostCenter updates,
                                             Authentication authentication) {
        UserSessionDto user = accessControlService.sessionUser(authentication);
        return costCenterRepository.findById(id).map(costCenter -> {
            if (!accessControlService.canAccessCostCenter(user, costCenter)
                    || !accessControlService.canManageCostCenters(user)) {
                return ResponseEntity.status(HttpStatus.FORBIDDEN).<CostCenter>build();
            }
            if (updates.getName() != null) costCenter.setName(updates.getName());
            if (updates.getPath() != null) costCenter.setPath(updates.getPath());
            if (updates.getVisible() != null) costCenter.setVisible(updates.getVisible());
            if (updates.getIsExtern() != null) costCenter.setIsExtern(updates.getIsExtern());
            return ResponseEntity.ok(costCenterRepository.save(Objects.requireNonNull(costCenter)));
        }).orElse(ResponseEntity.notFound().build());
    }

    @GetMapping("/{id}/addresses")
    public ResponseEntity<List<CostCenterAddress>> getAddresses(@PathVariable @NonNull Long id, Authentication authentication) {
        UserSessionDto user = accessControlService.sessionUser(authentication);
        CostCenter costCenter = costCenterRepository.findById(id).orElse(null);
        if (costCenter == null) {
            return ResponseEntity.notFound().build();
        }
        if (!accessControlService.canAccessCostCenter(user, costCenter)) {
            return ResponseEntity.status(HttpStatus.FORBIDDEN).build();
        }
        return ResponseEntity.ok(costCenterAddressRepository.findByCostCenterId(id));
    }

    @PostMapping("/{id}/addresses")
    public ResponseEntity<CostCenterAddress> addAddress(@PathVariable @NonNull Long id,
                                                        @RequestBody CostCenterAddress address,
                                                        Authentication authentication) {
        UserSessionDto user = accessControlService.sessionUser(authentication);
        CostCenter costCenter = costCenterRepository.findById(id).orElse(null);
        if (costCenter == null) {
            return ResponseEntity.notFound().build();
        }
        if (!accessControlService.canAccessCostCenter(user, costCenter)
                || !accessControlService.canManageCostCenters(user)) {
            return ResponseEntity.status(HttpStatus.FORBIDDEN).build();
        }
        address.setCostCenterId(id);
        return ResponseEntity.ok(costCenterAddressRepository.save(address));
    }
}
