#pragma once
#include "drogon/utils/Utilities.h"
#include <drogon/exports.h>
#include <drogon/HttpRequest.h>
#include <unordered_map>
#include <string>
#include <vector>
#include <memory>
#include <string_view>
namespace drogon
{
class HttpFileImpl;
class DROGON_EXPORT HttpFile
{
  public:
    explicit HttpFile(std::shared_ptr<HttpFileImpl> &&implPtr) noexcept;
    const std::string &getFileName() const noexcept;
    std::string_view getFileExtension() const noexcept;
    const std::string &getItemName() const noexcept;
    FileType getFileType() const noexcept;
    void setFileName(const std::string &fileName) noexcept;
    void setFile(const char *data, size_t length) noexcept;
    int save() const noexcept;
    int save(const std::string &path) const noexcept;
    int saveAs(const std::string &fileName) const noexcept;
    std::string_view fileContent() const noexcept
    {
        return std::string_view{fileData(), fileLength()};
    }
    size_t fileLength() const noexcept;
    drogon::ContentType getContentType() const noexcept;
    const char *fileData() const noexcept;
    std::string getMd5() const noexcept;
    const std::string &getContentTransferEncoding() const noexcept;
  private:
    std::shared_ptr<HttpFileImpl> implPtr_;
};
class DROGON_EXPORT MultiPartParser
{
  public:
    MultiPartParser(){};
    MultiPartParser(const MultiPartParser &other) = default;  
    MultiPartParser(MultiPartParser &&other) = default;       
    ~MultiPartParser(){};
    const std::vector<HttpFile> &getFiles() const;
    std::unordered_map<std::string, HttpFile> getFilesMap() const;
    const SafeStringMap<std::string> &getParameters() const;
    template <typename T>
    std::optional<T> getOptionalParameter(const std::string &key)
    {
        auto &params = getParameters();
        auto it = params.find(key);
        if (it != params.end())
        {
            try
            {
                return std::optional<T>(utils::fromString<T>(it->second));
            }
            catch (const std::exception &e)
            {
                LOG_ERROR << e.what();
                return std::optional<T>{};
            }
        }
        else
        {
            return std::optional<T>{};
        }
    }
    template <typename T>
    T getParameter(const std::string &key)
    {
        return getOptionalParameter<T>(key).value_or(T{});
    }
    int parse(const HttpRequestPtr &req);
  protected:
    std::vector<HttpFile> files_;
    SafeStringMap<std::string> parameters_;
    int parse(const HttpRequestPtr &req,
              const char *boundaryData,
              size_t boundaryLen);
    int parseEntity(const HttpRequestPtr &req,
                    const char *begin,
                    const char *end);
};
using FileUpload = MultiPartParser;
}  