package at.procon.eventhub.service;

import at.procon.eventhub.dto.CardSlot;
import at.procon.eventhub.dto.CardStatus;
import at.procon.eventhub.dto.DriverCardRefDto;
import at.procon.eventhub.dto.DrivingStatus;
import at.procon.eventhub.dto.EventDetailsDto;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.math.BigDecimal;
import java.util.LinkedHashMap;
import java.util.Map;
import org.springframework.stereotype.Component;

@Component
public class EventDetailsFactory {

    private final ObjectMapper objectMapper;

    public EventDetailsFactory(ObjectMapper objectMapper) {
        this.objectMapper = objectMapper;
    }

    public EventDetailsDto driverActivity(CardSlot cardSlot, CardStatus cardStatus, DrivingStatus drivingStatus) {
        Map<String, Object> attributes = new LinkedHashMap<>();
        put(attributes, "cardSlot", cardSlot);
        put(attributes, "cardStatus", cardStatus);
        put(attributes, "drivingStatus", drivingStatus);
        return new EventDetailsDto("DRIVER_ACTIVITY", objectMapper.valueToTree(attributes));
    }

    public EventDetailsDto driverCard(CardSlot cardSlot, CardStatus cardStatus) {
        return driverCard(cardSlot, cardStatus, null);
    }

    public EventDetailsDto driverCard(CardSlot cardSlot, CardStatus cardStatus, DriverCardRefDto driverCard) {
        Map<String, Object> attributes = new LinkedHashMap<>();
        put(attributes, "cardSlot", cardSlot);
        put(attributes, "cardStatus", cardStatus);
        if (driverCard != null && driverCard.hasValue()) {
            put(attributes, "cardNation", driverCard.nation());
            put(attributes, "cardNumber", driverCard.number());
        }
        return new EventDetailsDto("DRIVER_CARD", objectMapper.valueToTree(attributes));
    }

    public EventDetailsDto position(String reason) {
        Map<String, Object> attributes = new LinkedHashMap<>();
        put(attributes, "positionReason", reason);
        return new EventDetailsDto("POSITION", objectMapper.valueToTree(attributes));
    }

    public EventDetailsDto place(String country, String region) {
        Map<String, Object> attributes = new LinkedHashMap<>();
        put(attributes, "country", country);
        put(attributes, "region", region);
        return new EventDetailsDto("PLACE", objectMapper.valueToTree(attributes));
    }

    public EventDetailsDto borderCrossing(String countryFrom, String countryTo) {
        Map<String, Object> attributes = new LinkedHashMap<>();
        put(attributes, "countryFrom", countryFrom);
        put(attributes, "countryTo", countryTo);
        return new EventDetailsDto("BORDER_CROSSING", objectMapper.valueToTree(attributes));
    }

    public EventDetailsDto loadUnload(String operation) {
        Map<String, Object> attributes = new LinkedHashMap<>();
        put(attributes, "operation", operation);
        return new EventDetailsDto("LOAD_UNLOAD", objectMapper.valueToTree(attributes));
    }

    public EventDetailsDto specificCondition() {
        return new EventDetailsDto("SPECIFIC_CONDITION", objectMapper.createObjectNode());
    }

    public EventDetailsDto speeding(BigDecimal speedKmh, BigDecimal permittedSpeedKmh) {
        return speeding(null, speedKmh, permittedSpeedKmh);
    }

    public EventDetailsDto speeding(BigDecimal avgSpeedKmh, BigDecimal maxSpeedKmh, BigDecimal permittedSpeedKmh) {
        Map<String, Object> attributes = new LinkedHashMap<>();
        put(attributes, "avgSpeedKmh", avgSpeedKmh);
        put(attributes, "maxSpeedKmh", maxSpeedKmh);
        put(attributes, "permittedSpeedKmh", permittedSpeedKmh);
        if (maxSpeedKmh != null && permittedSpeedKmh != null) {
            put(attributes, "overspeedKmh", maxSpeedKmh.subtract(permittedSpeedKmh));
        }
        return new EventDetailsDto("SPEEDING", objectMapper.valueToTree(attributes));
    }

    public JsonNode payloadFromMap(Map<String, Object> payload) {
        return objectMapper.valueToTree(payload == null ? Map.of() : payload);
    }

    private void put(Map<String, Object> target, String key, Object value) {
        if (value != null) {
            target.put(key, value instanceof Enum<?> enumValue ? enumValue.name() : value);
        }
    }
}
