#pragma once

#include <pugixml.hpp>
#include <string>
#include <vector>

#include "utils.hpp"

using namespace pugi;

/**
* Represents a feed item or article.
*
* Typically you won't need to manually initialzie FeedItem objects, you can
* instead create a Feed object and extract its FeedItems using
* Feed::get_items().
*
* In case some value cannot be found, it will just contain an empty string.
*/
class FeedItem {
private:
    xml_node item_node;
    std::string website_url;

    std::string title;
    std::string content;
    std::string url;
    std::string media_url;
    std::string pub_date;
    std::string img_url;
    std::string author_name;
    std::string author_url;

    /**
    * Tries to extract the item url and returns it.
    */
    std::string extract_url();

    /**
    * Tries to extract the item media url and returns it.
    * This is typically used by podcasts
    */
    std::string extract_media_url();

    static inline const std::vector<ExtractionParam> __IMG_URL_PARAMS{
        {ExtractionParam::ParamType::ATTRIBUTE, {"thumbnail"}, "url"},
        {ExtractionParam::ParamType::ATTRIBUTE, {"media:thumbnail"}, "url"},
        {ExtractionParam::ParamType::ATTRIBUTE, {"group", "thumbnail"}, "url"},
        {ExtractionParam::ParamType::ATTRIBUTE, {"media:group", "thumbnail"}, "url"},
        {ExtractionParam::ParamType::ATTRIBUTE, {"media:group", "media:thumbnail"}, "url"}
    };
    /**
    * Tries to extract the url of an image representing the item and returns
    * it.
    */
    std::string extract_img_url();

    /**
    * Makes relative urls absolute and/or adds the protocol if not present.
    * This fixing is done in place on the string passed.
    */
    void fix_url(std::string &s);

    static inline const std::vector<ExtractionParam> __CONTENT_PARAMS{
        {ExtractionParam::ParamType::CHILD, {"content"}},
        {ExtractionParam::ParamType::CHILD, {"content:encoded"}},
        {ExtractionParam::ParamType::CHILD, {"description"}},
        {ExtractionParam::ParamType::CHILD, {"summary"}},
        {ExtractionParam::ParamType::CHILD, {"media:group", "media:description"}}
    };
    static inline const std::vector<ExtractionParam> __PUB_DATE_PARAMS{
        {ExtractionParam::ParamType::CHILD, {"pubDate"}},
        {ExtractionParam::ParamType::CHILD, {"published"}},
        {ExtractionParam::ParamType::CHILD, {"updated"}},
        {ExtractionParam::ParamType::CHILD, {"date"}},
        {ExtractionParam::ParamType::CHILD, {"dc:date"}}
    };
    static inline const std::vector<ExtractionParam> __AUTHOR_NAME_PARAMS{
        {ExtractionParam::ParamType::CHILD, {"author", "name"}},
        {ExtractionParam::ParamType::CHILD, {"author"}},
        {ExtractionParam::ParamType::CHILD, {"dc:creator"}},
        {ExtractionParam::ParamType::CHILD, {"creator"}},
        {ExtractionParam::ParamType::CHILD, {"itunes:author"}},
    };
    static inline const std::vector<ExtractionParam> __AUTHOR_URL_PARAMS{
        {ExtractionParam::ParamType::CHILD, {"author", "uri"}}
    };
    /**
    * Entry point of the class, parses all the relevant content. Called by
    * the constructor.
    */ 
    void parse();

public:
    /**
    * Constructs the FeedItem object from a `pugi::xml_node` representing a
    * feed item. The website base url should also be provided so that any
    * eventual urls formed like "some/path" or "/some/absolute/path" can be
    * appropriately completed.
    * 
    * @param item_node a `pugi::xml_node` object representing a feed item
    * @param website_url the base url of the website that the feed belongs to
    */
    FeedItem(
            xml_node item_node, std::string website_url
    ): item_node{item_node}, website_url{website_url} {
        parse();
    }

    std::string get_title() { return title; }
    std::string get_content() { return content; }
    std::string get_url() { return url; }
    std::string get_media_url() { return media_url; }
    std::string get_pub_date() { return pub_date; }
    std::string get_img_url() { return img_url; }
    std::string get_author_name() { return author_name; }
    std::string get_author_url() { return author_url; }

    /**
    * Represents the FeedItem object (itself) as a json, returned as a string.
    */
    std::string to_json();
};
