package Database;

import Gson.GsonFormatter;
import Gson.JsonHelper;
import com.google.gson.JsonObject;

import java.text.DecimalFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.regex.Pattern;

// Source : https://developer.flightstats.com/api-docs/fids/v1/fidsresponse

public class FisData {
    public int id;
    // example GA for Garuda Indonesia
    public String AirlineCode;
    // example 123
    public String FlightNumber;
    // Departure or Arrival
    public char DA;
    // Domestic or International
    public char DI;
    // CityDetail of the origin of the flight
    //public CityDetail Origin;
    public String Origin;
    // CityDetail of the destination of the flight
    //public CityDetail[] Destination;
    public String Destination;
    // example D1
    public String Gate;
    // example Terminal 2
    public String Terminal;
    // Conveyor Belt 1
    public String BaggageClaim;
    // Check-in Counter 1
    public String CheckinCounter;
    // when this data last updated
    public LocalDateTime lastUpdated;
    // scheduled time of arrival or departure
    public LocalDateTime scheduledTime;
    // estimated time of arrival or departure
    public LocalDateTime estimatedTime;
    // actual time of arrival or departure
    public LocalDateTime actualTime;
    // scheduled time of gate departure or arrival
    public LocalDateTime gateScheduledTime;
    // estimated time of gate departure or arrival
    public LocalDateTime gateEstimatedTime;
    // actual time of gate departure or arrival
    public LocalDateTime gateActualTime;
    // optinal data, example : Cloudy
    public String weather;
    // optional data, example : 25.6
    public double temperatureC;
    public  String Remark;
    // for AAS Purpose
    public String IsRead;

    @SuppressWarnings("unused")
    public static FisData CreateFromJsonObject(JsonObject vv){
        if (vv!=null){
            FisData data = new FisData();
            data.id = JsonHelper.GetIntValue(vv, "id", 0);
            data.setAirlineCode(JsonHelper.GetStringValue(vv, "AirlineCode", null));
            data.setFlightNumber(JsonHelper.GetStringValue(vv, "FlightNumber", null));
            data.setDI(JsonHelper.GetCharacterValue(vv, "DI", null));
            data.setDA(JsonHelper.GetCharacterValue(vv, "DA", null));
            //data.setOrigin(JsonHelper.GetCityDetailValue(vv, "Origin", null));
            data.Origin = JsonHelper.GetStringValue(vv, "Origin", null);
            //data.setDestination(JsonHelper.GetCityDetailValues(vv, "Destination", null));
            data.Destination = JsonHelper.GetStringValue(vv, "Destination", null);
            data.Gate = JsonHelper.GetStringValue(vv, "Gate", null);
            data.Terminal =JsonHelper.GetStringValue(vv, "Terminal", null);
            data.BaggageClaim = JsonHelper.GetStringValue(vv, "BaggageClaim", null);
            data.CheckinCounter = JsonHelper.GetStringValue(vv, "CheckinCounter", null);
            data.setLastUpdated(JsonHelper.GetLocalDateTimeValue(vv, "LastUpdated", null));
            data.setScheduledTime(JsonHelper.GetLocalDateTimeValue(vv, "ScheduledTime", null));
            data.setEstimatedTime(JsonHelper.GetLocalDateTimeValue(vv, "EstimatedTime", null));
            data.setActualTime(JsonHelper.GetLocalDateTimeValue(vv, "ActualTime", null) );
            data.setGateScheduledTime(JsonHelper.GetLocalDateTimeValue(vv, "GateScheduledTime", null));
            data.setGateEstimatedTime(JsonHelper.GetLocalDateTimeValue(vv, "GateEstimatedTime", null));
            data.setGateActualTime(JsonHelper.GetLocalDateTimeValue(vv, "GateActualTime", null));
            data.weather = JsonHelper.GetStringValue(vv, "Weather", null);
            data.temperatureC = JsonHelper.GetDoubleValue(vv, "TemperatureC", 0.0);
            data.Remark = JsonHelper.GetStringValue(vv, "Remark", null);
            data.IsRead = JsonHelper.GetStringValue(vv, "IsRead", null);
            return data;
        }
        return null;
    }

    @Override
    public String toString(){
        return GsonFormatter.toJson(this);
    }

    @SuppressWarnings("unused")
    public JsonObject toJsonObject(){
        return GsonFormatter.toJsonObject(this, FisData.class);
    }

    public static String LocalDateTimeToString(LocalDateTime value){
        if (value!=null){
            try {
                return dtf.format(value);
            } catch (Exception ignored) {
            }
        }
        return "";
    }

    /**
     * Set Airline Code
     * <br/>Airline code must be 2 characters, if longer than 2 characters, it will be truncated
     * <br/>Airline code will be converted to uppercase
     * @param airlineCode Airline Code
     */
    @SuppressWarnings("unused")
    public void setAirlineCode(String airlineCode) {
        if (airlineCode!=null && !airlineCode.isEmpty()){
            // airline code must be 2 characters
            if (airlineCode.length()>2) airlineCode = airlineCode.substring(0,2);
            this.AirlineCode = airlineCode.toUpperCase();
        }
    }

    // flight number pattern, must consist of 1-4 digits
    public static final Pattern flightNumberPattern = Pattern.compile("^[0-9]{1,4}$");
    /**
     * Set Flight Number
     * <br/>Flight number must be 1-4 digits (0-9)
     * @param flightNumber Flight Number
     */
    @SuppressWarnings("unused")
    public void setFlightNumber(String flightNumber) {
        if (flightNumber!=null && !flightNumber.isEmpty()) {
            // flight number must be 1-4 digits
            if (flightNumberPattern.matcher(flightNumber).matches()) {
                this.FlightNumber = flightNumber;
            }
        }
    }

    /**
     * Set the DI (Domestic or International)
     * Accepted value is 'D' for Domestic and 'I' for International
     * @param DI DI value
     */
    @SuppressWarnings("unused")
    public void setDI(Character DI) {
        if (DI!=null){
            if (DI == 'D' || DI == 'I') {
                this.DI = DI;
            } else if (DI=='d' || DI=='i'){
                this.DI = Character.toUpperCase(DI);
            }
        }

    }

    /**
     * Set the DA (Departure or Arrival)
     * Accepted value is 'D' for Departure and 'A' for Arrival
     * @param DA DA value
     */
    @SuppressWarnings("unused")
    public void setDA(Character DA) {
        if (DA!=null){
            if (DA == 'D' || DA == 'A') {
                this.DA = DA;
            } else if (DA == 'd' || DA == 'a') {
                this.DA = Character.toUpperCase(DA);
            }
        }

    }



    /**
     * Get the time of the flight
     * If actual time is available, return actual time
     * If actual time is not available, return estimated time
     * If estimated time is not available, return scheduled time
     * if not available, return null
     * @return departure or arrival time, depend of the data
     */
    public LocalDateTime getCurrentTime(){
        if (actualTime != null) {
            return actualTime;
        } else if (estimatedTime != null) {
            return estimatedTime;
        } else {
            return scheduledTime;
        }
    }

    /**
     * Get the time of the gate
     * if actual time is available, return actual time
     * if actual time is not available, return estimated time
     * if estimated time is not available, return scheduled time
     * if not available, return null
     * @return gate departure or arrival time, depend of the data
     */
    @SuppressWarnings("unused")
    public LocalDateTime getGateCurrentTime(){
        if (gateActualTime != null) {
            return gateActualTime;
        } else if (gateEstimatedTime != null) {
            return gateEstimatedTime;
        } else {
            return gateScheduledTime;
        }
    }

    public static final DecimalFormat df = new DecimalFormat("#.#");

    /**
     * Get the flight code
     * <br/>is a combination of <b>AirlineCode</b> and <b>FlightNumber</b>
     * <br/>example : GA123
     * @return flight code
     */
    @SuppressWarnings("unused")
    public String getFlight(){
        return AirlineCode + FlightNumber;
    }

    /**
     * Check if the flight is delayed
     * <br/>if the current time is after the scheduled time, then the flight is delayed
     * @return true if the flight is delayed
     */
    @SuppressWarnings("unused")
    public boolean Delayed(){
        return getCurrentTime().isAfter(scheduledTime);
    }
    public static final DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    public static boolean CorrectTimeFormat(String time){
        if (time!=null) {
            if (!time.isEmpty()){
                try {
                    LocalDateTime.parse(time, dtf);
                    return true;
                } catch (Exception ignored) {
                }
            }
        }
        return false;
    }
    /**
     * Set the scheduled time of the flight
     * <br/>the time must be in the format of "yyyy-MM-dd HH:mm:ss"
     * <br/>if DA is 'D', the time is the departure time
     * <br/>if DA is 'A', the time is the arrival time
     * @param scheduledTime scheduled time
     */
    @SuppressWarnings("unused")
    public void setScheduledTime(String scheduledTime) {
        if (CorrectTimeFormat(scheduledTime)) setScheduledTime(LocalDateTime.parse(scheduledTime, dtf));

    }

    /**
     * Set the scheduled time of the flight
     * <br/>if DA is 'D', the time is the departure time
     * <br/>if DA is 'A', the time is the arrival time
     * @param scheduledTime scheduled time
     */
    @SuppressWarnings("unused")
    public void setScheduledTime(LocalDateTime scheduledTime) {
        this.scheduledTime = scheduledTime;
    }

    /**
     * Set the estimated time
     * <br/>the time must be in the format of "yyyy-MM-dd HH:mm:ss"
     * <br/>if DA is 'D', the time is the departure time
     * <br/>if DA is 'A', the time is the arrival time
     * @param estimatedTime estimated time
     */
    @SuppressWarnings("unused")
    public void setEstimatedTime(String estimatedTime) {
        if (CorrectTimeFormat(estimatedTime)) setEstimatedTime(LocalDateTime.parse(estimatedTime, dtf));
    }

    /**
     * Set the estimated time
     * <br/>if DA is 'D', the time is the departure time
     * <br/>if DA is 'A', the time is the arrival time
     * @param estimatedTime estimated time
     */
    @SuppressWarnings("unused")
    public void setEstimatedTime(LocalDateTime estimatedTime) {
        this.estimatedTime = estimatedTime;
    }

    /**
     * Set the actual time
     * <br/>the time must be in the format of "yyyy-MM-dd HH:mm:ss"
     * <br/>if DA is 'D', the time is the departure time
     * <br/>if DA is 'A', the time is the arrival time
     * @param actualTime actual time
     */
    @SuppressWarnings("unused")
    public void setActualTime(String actualTime) {
        if (CorrectTimeFormat(actualTime)) setActualTime(LocalDateTime.parse(actualTime, dtf));
    }

    /**
     * Set the actual time
     * <br/>if DA is 'D', the time is the departure time
     * <br/>if DA is 'A', the time is the arrival time
     * @param actualTime actual time
     */
    @SuppressWarnings("unused")
    public void setActualTime(LocalDateTime actualTime) {
        this.actualTime = actualTime;
    }

    /**
     * Set the gate scheduled time
     * <br/>the time must be in the format of "yyyy-MM-dd HH:mm:ss"
     *
     * @param gateScheduledTime gate scheduled time
     */
    @SuppressWarnings("unused")
    public void setGateScheduledTime(String gateScheduledTime) {
        if (CorrectTimeFormat(gateScheduledTime)) setGateScheduledTime(LocalDateTime.parse(gateScheduledTime, dtf));
    }

    /**
     * Set the gate scheduled time
     *
     * @param gateScheduledTime gate scheduled time
     */
    @SuppressWarnings("unused")
    public void setGateScheduledTime(LocalDateTime gateScheduledTime) {
        this.gateScheduledTime = gateScheduledTime;
    }

    /**
     * Set the gate estimated time
     * <br/>the time must be in the format of "yyyy-MM-dd HH:mm:ss"
     * @param gateEstimatedTime gate estimated time
     */
    @SuppressWarnings("unused")
    public void setGateEstimatedTime(String gateEstimatedTime) {
        if (CorrectTimeFormat(gateEstimatedTime)) setGateEstimatedTime(LocalDateTime.parse(gateEstimatedTime, dtf));
    }

    /**
     * Set the gate estimated time
     * @param gateEstimatedTime gate estimated time
     */
    @SuppressWarnings("unused")
    public void setGateEstimatedTime(LocalDateTime gateEstimatedTime) {
        this.gateEstimatedTime = gateEstimatedTime;
    }

    /**
     * Set the gate actual time
     * <br/>the time must be in the format of "yyyy-MM-dd HH:mm:ss"
     * @param gateActualTime gate actual time
     */
    @SuppressWarnings("unused")
    public void setGateActualTime(String gateActualTime) {
        if (CorrectTimeFormat(gateActualTime)) setGateActualTime(LocalDateTime.parse(gateActualTime, dtf));
    }

    /**
     * Set the gate actual time
     * @param gateActualTime gate actual time
     */
    @SuppressWarnings("unused")
    public void setGateActualTime(LocalDateTime gateActualTime) {
        this.gateActualTime = gateActualTime;
    }

    /**
     * Set the last updated time
     * <br/>the time must be in the format of "yyyy-MM-dd HH:mm:ss"
     * @param lastUpdated last updated time
     */
    @SuppressWarnings("unused")
    public void setLastUpdated(String lastUpdated) {
        if (CorrectTimeFormat(lastUpdated)) this.lastUpdated = LocalDateTime.parse(lastUpdated, dtf);
    }

    /**
     * Set the last updated time
     * @param lastUpdated last updated time
     */
    @SuppressWarnings("unused")
    public void setLastUpdated(LocalDateTime lastUpdated) {
        this.lastUpdated = lastUpdated;
    }

    /**
     * Set the destination of the flight
     * @param CityName City Name, example : Tangerang
     * @param AirportName Airport Name, example : Soekarno-Hatta International Airport
     * @param AirportCode Airport Code, example : CGK
     * @param StateCode State Code, example : Banten
     * @param Country Country, example : Indonesia
     */
//    @SuppressWarnings("unused")
//    public void setOrigin(String CityName, String AirportName, String AirportCode, String StateCode, String Country){
//        setOrigin(new CityDetail(CityName, AirportName, AirportCode, StateCode, Country));
//    }

    /**
     * Set the origin of the flight
     * @param origin CityDetail of the origin
     */
 //   @SuppressWarnings("unused")
//    public void setOrigin(CityDetail origin) {
//        this.Origin = origin;
//    }

    /**
     * Set the destination of the flight
     * @param destination CityDetail of the destination
     */
//    @SuppressWarnings("unused")
//    public void setDestination(CityDetail... destination) {
//        this.Destination = destination;
//    }
}
