package cloud.hmml.mmw;

import android.content.Context;
import android.os.AsyncTask;
import android.os.Build;
import android.util.Log;

import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.google.gson.stream.JsonReader;

import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;


public class ForecastFetcher {
    final public static String BASE_URL = "https://mmw.hmml.cloud/api/v1/forecasts/";
    public String areaId;
    public String areaNs;
    public Context context;

    public ForecastFetcher(Context context, String areaNs, String areaId) {
        this.areaNs = areaNs;
        this.areaId = areaId;
        this.context = context;
    }

    public void save(ConfigManager config) {
        this.save(config, null);
    }


    public void save(ConfigManager config, Runnable callback) {

        class JsonFetcher extends AsyncTask<Void, Void, JsonObject> {
            private ConfigManager config;
            private Runnable callback;

            public JsonFetcher(ConfigManager config, Runnable callback) {
                this.config = config;
                this.callback = callback;
            }

            @Override
            protected JsonObject doInBackground(Void... voids) {
                return ForecastFetcher.this.getJson();
            }

            @Override
            protected void onPostExecute(JsonObject json) {
                if (json == null) {
                    Log.e("forecast-fetcher", "Failed to fetch forecast JSON.");
                    return;
                }

                SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
                Date reportedAt = null;
                Calendar reportedAtCal = null;
                try {
                    reportedAt = df.parse(json.getAsJsonPrimitive("reported_at").getAsString());
                    config.saveReportedAt(reportedAt);
                } catch (ParseException e) {
                    Log.e("forecast-fetcher", "Failed to parse reported_at!");
                    e.printStackTrace();
                } catch (NullPointerException e) {
                    // ignore!
                }

                int index = 1;
                for (JsonElement j: json.getAsJsonArray("daily_forecasts")) {
                    JsonObject day = j.getAsJsonObject();

                    String label = day.getAsJsonPrimitive("weather_label").getAsString();
                    String ident = day.getAsJsonPrimitive("weather_symbol").getAsString();
                    Integer temp_max = null;
                    Integer temp_min = null;
                    Integer pop = null;
                    try {
                        temp_max = day.getAsJsonPrimitive("temp_max").getAsInt();
                    } catch (ClassCastException e) {
                        // ignroe
                    }
                    try {
                        temp_min = day.getAsJsonPrimitive("temp_min").getAsInt();
                    } catch (ClassCastException e) {
                        // ignroe
                    }
                    try {
                        pop = day.getAsJsonPrimitive("pop").getAsInt();
                    } catch (ClassCastException e) {
                        // ignroe
                    }

                    config.saveWeather(index, ident, label, temp_min, temp_max, pop);

                    index++;
                    if (index > 2) break;
                }

                config.saveUpdatedAt();
                Log.d("forecast-fetcher", "Forecast has been fetched successfully.");
                if (callback != null)
                    callback.run();
            }
        }

        new JsonFetcher(config, callback).execute();
    }

    protected JsonObject getJson() {
        URL url = null;
        HttpURLConnection httpconn = null;
        try {
            url = new URL(BASE_URL + areaNs + "/" + areaId + ".json");
        } catch (MalformedURLException e) {
            Log.e("forecast-fetcher", "BAD URL on getting json: " + e.getMessage());
            e.printStackTrace();
            return null;
        }
        try {
            httpconn = (HttpURLConnection) url.openConnection();
        } catch (IOException e) {
            Log.e("forecast-fetcher", "Failed to open connection to get JSON: " + e.getMessage());
            e.printStackTrace();
            return null;
        }
        httpconn.addRequestProperty("X-Requested-With", "Android cloud.hmml.mmw");
        httpconn.addRequestProperty("User-Agent", "cloud.hmml.mmw/" + BuildConfig.VERSION_NAME + " (Android " + Build.VERSION.RELEASE + "; " + Build.DEVICE + ")");
        try {
            httpconn.connect();
        } catch (IOException e) {
            Log.e("forecast-fetcher", "Failed to request to get JSON: " + e.getMessage());
            e.printStackTrace();
            return null;
        }

        try {
            try {
                int retcode = httpconn.getResponseCode();
                if (retcode != 200) {
                    Log.e("forecast-fetcher", "Invalid return code " + retcode + " on getting JSON");
                    return null;
                }
            } catch (IOException e) {
                Log.e("forecast-fetcher", "Failed to get response code on getting JSON: " + e.getMessage());
                e.printStackTrace();
                return null;
            }

            try {
                return (new JsonParser()).parse(new JsonReader(new InputStreamReader(httpconn.getInputStream()))).getAsJsonObject();
            } catch (IOException e) {
                Log.e("forecast-fetcher", "Failed to read stream data on getting JSON: " + e.getMessage());
                e.printStackTrace();
                return null;
            }
        } finally {
            httpconn.disconnect();
        }
    }
}
