package com.example.fitbot.exercise;

import com.example.fitbot.util.path.AnglePath;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;

public class ExerciseManager {

    private static final String HOST_ADDRESS = "http://145.92.8.132:443";

    // The value of these property variables must be equivalent of
    // the JSON data that the database sends back.
    // If this is not the case then the exercise retrieval will fail.
    private static final String PROPERTY_EXERCISE_DURATION = "duration";
    private static final String PROPERTY_EXERCISE_ID = "exerciseId";
    private static final String PROPERTY_MUSCLE_GROUP = "muscleGroup";
    private static final String PROPERTY_IMAGE_URL = "imageUrl";
    private static final String PROPERTY_VIDEO_URL = "videoUrl";
    private static final String PROPERTY_DESC = "description";
    private static final String PROPERTY_SHORT_DESC = "shortDescription";
    private static final String PROPERTY_PATH = "path";
    private static final String PROPERTY_NAME = "name";

    public static final int SENSOR_COUNT = 2;

    private static final String[] REQUIRED_PROPERTIES = {
            PROPERTY_MUSCLE_GROUP, PROPERTY_DESC,PROPERTY_SHORT_DESC, PROPERTY_IMAGE_URL,
            PROPERTY_VIDEO_URL, PROPERTY_NAME, PROPERTY_PATH,
            PROPERTY_EXERCISE_DURATION, PROPERTY_EXERCISE_ID
    };

    public static final int DEFAULT_EXERCISE_REPETITIONS = 10;
    public static final float EXERCISE_ERROR_MARGIN = 1.0f;
    public static final float EXERCISE_TIME_SCALING_FACTOR = 1.0f;

    // Fields representing the statistics of the user
    public static int TOTAL_REPETITIONS_REQUIRED = 0;
    public static int TOTAL_REPETITIONS_PERFORMED = 0;
    public static int TOTAL_EXERCISES_PREFORMED = 0;


    /**
     * Function for sending an HTTP request to the server.
     *
     * @param url         The URL to send the request to.
     * @param method      The method to use for the request, e.g. GET or POST.
     * @param contentType The content type of the request.
     * @param body        The body of the request.
     * @return The response from the server.
     */
    public static String sendHTTP(String url, String method, String contentType, String body) {
        try {
            URLConnection connection = new URL(url).openConnection();
            connection.setDoOutput(true);
            connection.setDoInput(true);
            connection.addRequestProperty("Content-Type", contentType);
            connection.addRequestProperty("Request-Method", method);
            connection.connect();
            // Send a body if it is present
            if (body != null)
                connection.getOutputStream().write(body.getBytes());

            InputStream stream = connection.getInputStream();
            BufferedReader reader = new BufferedReader(new InputStreamReader(stream));
            StringBuilder builder = new StringBuilder();
            String line;
            while ((line = reader.readLine()) != null) {
                builder.append(line);
            }
            return builder.toString();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * Function for retrieving an exercise from the Raspberry Pi Database.
     *
     * @return The exercise, if it exists on the server. Otherwise null.
     */
    public static Exercise fetchExerciseFromDatabase() {
        String response = sendHTTP(
                HOST_ADDRESS, "POST", "application/json", "{}"
        );
        // Validate the response
        if (response != null) {
            try {
                System.out.println(response);
                JsonObject content = JsonParser.parseString(response).getAsJsonObject();

                // Ensure all required properties are present
                for (String property : REQUIRED_PROPERTIES) {
                    if (!content.has(property)) {
                        System.out.println("Missing property: " + property);
                        return null;
                    }
                }

                // Path data is split into two parts, due to the left and right hand.
                // If one wants to add support for more sensors, one will have to adjust the Exercise
                // class to support more paths.
                System.out.println(content.get(PROPERTY_PATH).getAsString());

                AnglePath[] paths = AnglePath.fromString(content.get(PROPERTY_PATH).getAsString());

                if (paths.length != SENSOR_COUNT) {
                    System.out.println("Invalid path data.");
                    return null;
                }

                return new Exercise(
                        EMuscleGroup.parse(content.get(PROPERTY_MUSCLE_GROUP).getAsString()),
                        content.get(PROPERTY_NAME).getAsString(),
                        content.get(PROPERTY_SHORT_DESC).getAsString(),
                        content.get(PROPERTY_DESC).getAsString(),
                        content.get(PROPERTY_IMAGE_URL).getAsString(),
                        content.get(PROPERTY_VIDEO_URL).getAsString(),
                        paths[0],
                        paths[1],
                        content.get(PROPERTY_EXERCISE_DURATION).getAsInt()
                );
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return null;
    }
}
