package com.lingniu.ingest.vehiclestat.jt808;

import com.lingniu.ingest.sink.kafka.proto.TelemetryField;
import com.lingniu.ingest.sink.kafka.proto.VehicleEnvelope;

import java.time.Instant;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Optional;

public final class Jt808LocationPointExtractor {

    public Optional<Jt808LocationPoint> extract(VehicleEnvelope envelope) {
        if (envelope == null
                || !"JT808".equalsIgnoreCase(envelope.getSource())
                || !envelope.hasTelemetrySnapshot()
                || !"LOCATION".equalsIgnoreCase(envelope.getTelemetrySnapshot().getEventType())) {
            return Optional.empty();
        }
        Map<String, String> fields = fields(envelope);
        Double longitude = decimal(fields.get("longitude"));
        Double latitude = decimal(fields.get("latitude"));
        if (longitude == null || latitude == null || !validCoordinate(longitude, latitude)) {
            return Optional.empty();
        }

        String vin = clean(envelope.getVin());
        String phone = clean(envelope.getMetadataMap().getOrDefault("phone", ""));
        String vehicleKey = vehicleKey(vin, phone);
        if (vehicleKey.isBlank()) {
            return Optional.empty();
        }
        return Optional.of(new Jt808LocationPoint(
                vehicleKey,
                vin,
                phone,
                Instant.ofEpochMilli(envelope.getEventTimeMs()),
                longitude,
                latitude,
                decimal(fields.get("speed_kmh")),
                integer(fields.get("location_status_raw")),
                decimal(fields.get("total_mileage_km"))));
    }

    private static Map<String, String> fields(VehicleEnvelope envelope) {
        Map<String, String> out = new LinkedHashMap<>();
        for (TelemetryField field : envelope.getTelemetrySnapshot().getFieldsList()) {
            if (!field.getKey().isBlank()) {
                out.put(field.getKey(), field.getValue());
            }
        }
        return out;
    }

    private static String vehicleKey(String vin, String phone) {
        if (!vin.isBlank() && !"unknown".equalsIgnoreCase(vin)) {
            return vin;
        }
        return phone.isBlank() ? "" : "jt808:" + phone;
    }

    private static boolean validCoordinate(double longitude, double latitude) {
        return Double.isFinite(longitude)
                && Double.isFinite(latitude)
                && longitude >= -180.0
                && longitude <= 180.0
                && latitude >= -90.0
                && latitude <= 90.0;
    }

    private static Double decimal(String raw) {
        if (raw == null || raw.isBlank()) {
            return null;
        }
        try {
            double value = Double.parseDouble(raw);
            return Double.isFinite(value) ? value : null;
        } catch (NumberFormatException ignored) {
            return null;
        }
    }

    private static Long integer(String raw) {
        if (raw == null || raw.isBlank()) {
            return null;
        }
        try {
            return Long.parseLong(raw);
        } catch (NumberFormatException ignored) {
            return null;
        }
    }

    private static String clean(String value) {
        return value == null ? "" : value.trim();
    }
}
