package de.avatic.lcc.service.access;

import de.avatic.lcc.dto.configuration.nodes.userNodes.AddUserNodeDTO;
import de.avatic.lcc.dto.generic.NodeDTO;
import de.avatic.lcc.model.db.country.IsoCode;
import de.avatic.lcc.model.db.nodes.Node;
import de.avatic.lcc.repositories.country.CountryRepository;
import de.avatic.lcc.repositories.users.UserNodeRepository;
import de.avatic.lcc.service.transformer.generic.NodeTransformer;
import de.avatic.lcc.service.users.AuthorizationService;
import de.avatic.lcc.util.exception.badrequest.InvalidArgumentException;
import de.avatic.lcc.util.exception.badrequest.NotFoundException;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;

@Service
public class UserNodeService {
    private final CountryRepository countryRepository;
    private final UserNodeRepository userNodeRepository;
    private final AuthorizationService authorizationService;
    private final NodeTransformer nodeTransformer;

    public UserNodeService(CountryRepository countryRepository, UserNodeRepository userNodeRepository, AuthorizationService authorizationService, NodeTransformer nodeTransformer) {
        this.countryRepository = countryRepository;
        this.userNodeRepository = userNodeRepository;
        this.authorizationService = authorizationService;
        this.nodeTransformer = nodeTransformer;
    }

    public Node getUserNode(Integer id) {
        return userNodeRepository.getById(id).orElseThrow();
    }

    /**
     * Adds a user-specific node to the system based on the provided {@link AddUserNodeDTO}.
     *
     * @param dto the {@link AddUserNodeDTO} containing details about the user node to create, including name,
     *            address, geographic location, and country information.
     * @throws IllegalArgumentException if any required information in the DTO is missing or invalid.
     */
    public NodeDTO addUserNode(AddUserNodeDTO dto) {
        var userId = authorizationService.getUserId();

        Node node = new Node();

        if (dto.getName() == null || dto.getName().isBlank())
            throw new InvalidArgumentException("name set to blank value");
        if (dto.getAddress() == null || dto.getAddress().isBlank())
            throw new IllegalArgumentException("address set to blank value");
        if (dto.getLocation() == null)
            throw new InvalidArgumentException("location set to null value");

        node.setName(dto.getName());
        node.setAddress(dto.getAddress());
        node.setGeoLng(BigDecimal.valueOf(dto.getLocation().longitude()));
        node.setGeoLat(BigDecimal.valueOf(dto.getLocation().latitude()));
        node.setDestination(false);
        node.setSource(true);
        node.setIntermediate(false);
        node.setDeprecated(false);

        node.setCountryId(countryRepository.getByIsoCode(IsoCode.valueOf(dto.getCountry().getIsoCode())).orElseThrow(() -> new NotFoundException(NotFoundException.NotFoundType.COUNTRY, "iso code", dto.getCountry().getIsoCode())).getId());

        var id = userNodeRepository.add(userId, node);

        return nodeTransformer.toUserNodeDTO(userNodeRepository.getById(id).orElseThrow());
    }
}
