#ifndef HTTPS_HANDLER_H
#define HTTPS_HANDLER_H

#include <WiFiClientSecure.h>
#include "SD_MMC.h"

/**
 * @class HTTPSHandler
 *
 * This class provides functionality to handle HTTPS connections, including downloading,
 * uploading, and sending post requests. It uses a state machine internally to track the
 * status of downloads.
 */
class HTTPSHandler
{
public:
    /**
     * @enum HttpsState
     *
     * Enumerates the possible states for the https class.
     */
    enum class HttpsState
    {
        IDLE,       // Initial state, no download in progress.
        CONNECTING, // Connecting to the server.
        WAITING,    // Waiting for server response.
        COMPLETE,   // Response is complete.
        ERROR       // An error occurred during the download.
    };

    /**
     * @enum Type of http request
     */
    enum class RequestType
    {
        GET,
        DOWNLOAD,
        POST,
        UPLOAD
    };

    // A callback type that notifies about download progress.
    using ProgressCallback = void (*)(int bytesDownloaded, int totalBytes);

private:
    WiFiClientSecure _client;
    // The server's certificate for SSL/TLS connection. Typically the root CA certificate.
    const char *_serverCert;
    // Must be a domain name, not an IP address.
    const char *_host;
    // Range between 0 and 65535.
    int _port = 443;

    // Duration in seconds.
    uint8_t _downloadTimeout = 90;
    // Duration in seconds.
    uint8_t _responseTimeout = 100;

    // Callback function to get download progress updates.
    ProgressCallback _progressCallback = nullptr;
    // Current state of the download.
    HttpsState _currentState = HttpsState::IDLE;
    // Type of http request.
    RequestType _requestType;
    // Boundaries for upload.
    const String _BOUNDARY = "----WebKitFormBoundary7MA4YWxkTrZu0gW";

    String _response;

    // The File object where the downloaded data will be saved.
    File _destinationFile;
    // The path or endpoint on the server.
    const char *_path;
    // A header to be sent with the request.
    String _customHeader;

    /**
     * Establish a connection to the server.
     * @return true if connected successfully, false otherwise.
     */
    bool _connect();

    /**
     * Internal method to get the content length from the server's response headers.
     * @return The content length as an integer.
     */
    int _getContentLength();

    /**
     * Processes the server's response for a given request.
     * This method reads the available data from the client, appends it to
     * the internal response string, and updates the current state
     * of the HTTPSHandler based on the contents of the response.
     */
    void _processResponse();

    /**
     * Process the download once initiated.
     * @param dest The File object where the downloaded data will be saved.
     */
    void _processDownload(File &dest);

    /**
     * Get only the file name from a given path.
     */
    String _extractFileName(const String &fullPath);

    /**
     * Create boundary for multipart upload.
     * Used in http request header.
     */
    String _createBoundary(const String &fileNameToUpload);

public:
    /**
     * Constructor for the HTTPSHandler class.
     * @param host The server's domain or IP address.
     * @param port The port to connect on the server.
     * @param serverCert The server's certificate for SSL/TLS connection.
     */
    HTTPSHandler(const char *serverCert);

    /**
     * Destructor for the HTTPSHandler class.
     */
    ~HTTPSHandler();

    /**
     * Establish a connection to the server.
     * @param host The server host to connect to.
     * @param port The server port to connect to. Defaults to 443.
     * @param serverCert The server certificate. Defaults to nullptr.
     * @return true if connected successfully, false otherwise.
     */
    bool connect(const char *host, int port = 443, const char *serverCert = nullptr);

    /**
     * Retrieves the server's response for the most recent request.
     *
     * @return A string containing the full response from the server.
     */
    String getResponse() { return _response; }

    /**
     * Checks if the server's response for the most recent request is complete.
     *
     * @return True if the response is complete, otherwise false.
     */
    bool isResponseComplete() { return _currentState == HttpsState::COMPLETE; }

    /**
     * Set a callback function to get download progress updates.
     * @param callback A function pointer to the callback.
     */
    void setProgressCallback(ProgressCallback callback) { _progressCallback = callback; }

    /**
     * Get the current download state.
     * @return The current state of the download.
     */
    HttpsState getState() const { return _currentState; }

    /**
     * Set a custom header for the next HTTP request.
     * @param header The header string to set.
     */
    void setCustomHeader(const String &header) { _customHeader = header; }

    /**
     * Initiate the download process.
     * @param path The path or endpoint on the server from where to download.
     */
    void getRequest(const char *path);

    /**
     * Upload a file to the server.
     * @param path The path or endpoint on the server where to upload.
     * @param source The File object containing the data to be uploaded.
     * @param fileName The name that will be used for the uploaded file on the server.
     *                 If not specified, the name of the source file will be used.
     * @return true if the upload was successful, false otherwise.
     */
    bool uploadFile(const char *path, File &source, const String &fileName = "");

    /**
     * Send a POST request to the server.
     * @param path The path or endpoint on the server to send the POST request.
     * @param postData The data to be sent in the POST request.
     * @return true if the request was successful, false otherwise.
     */
    bool postRequest(const char *path, const String &postData);

    /**
     * Set the target from a given path and destination file.
     * @param path The path or endpoint on the server from where to download.
     * @param dest The File object where the downloaded data will be saved.
     */
    void setTarget(const char *sourcePath, File &dest);

    /**
     * Continue processing the state machine.
     */
    void advanceStateMachine();

    /**
     * Check if an error occurred during the download.
     * @return true if an error occurred, false otherwise.
     */
    bool isErrorOccurred() { return _currentState == HttpsState::ERROR; }

    /**
     * Close the current connection with the server.
     */
    void close();

    /**
     *
     */
    // void get(const String &url, Callback callback);
};

#endif // HTTPS_HANDLER_H
