import json
import sys

if sys.version_info >= (3,0):
  import urllib.parse
  dku_quote_fn = urllib.parse.quote
else:
  import urllib
  dku_quote_fn = urllib.quote

class DSSObjectDiscussions(object):
    """
    A handle to manage discussions on a DSS object.

    .. important::
        Do not create this class directly, instead use :meth:`dataikuapi.DSSClient.get_object_discussions` on any commentable DSS object.
    """
    def __init__(self, client, project_key, object_type, object_id):
        self.client = client
        self.project_key = project_key
        self.object_type = object_type
        self.object_id = object_id
        # encode in UTF-8 if its python2 and unicode
        if sys.version_info < (3,0) and isinstance(self.object_id, unicode):
            self.object_id = self.object_id.encode('utf-8')

    def list_discussions(self):
        """
        Gets the list of discussions on the object.

        :returns: list of discussions on the object
        :rtype: list of :class:`dataikuapi.dss.discussion.DSSDiscussion`
        """
        data = self.client._perform_json("GET", "/projects/%s/discussions/%s/%s/" % (self.project_key, self.object_type, self.object_id))
        return [DSSDiscussion(self.client, self.project_key, self.object_type, self.object_id, discu_data['id'], discu_data, False) for discu_data in data]

    def create_discussion(self, topic, message):
        """
        Creates a new discussion with one message.

        :param str topic: the discussion topic
        :param str message: the markdown formatted first message

        :returns: the newly created discussion
        :rtype: :class:`dataikuapi.dss.discussion.DSSDiscussion`
        """
        creation_data = {
            "topic" : topic,
            "reply" : message
        }
        discu_data = self.client._perform_json("POST", "/projects/%s/discussions/%s/%s/" % (self.project_key, self.object_type, self.object_id), body=creation_data)
        return DSSDiscussion(self.client, self.project_key, self.object_type, self.object_id, discu_data['id'], discu_data, True)

    def get_discussion(self, discussion_id):
        """
        Gets a specific discussion.

        :param str discussion_id: the discussion ID

        :returns: the discussion
        :rtype: :class:`dataikuapi.dss.discussion.DSSDiscussion`
        """
        discu_data = self.client._perform_json("GET", "/projects/%s/discussions/%s/%s/%s" % (self.project_key, self.object_type, self.object_id, discussion_id))
        return DSSDiscussion(self.client, self.project_key, self.object_type, self.object_id, discussion_id, discu_data, True)

class DSSDiscussion(object):
    """
    A handle to interact with a discussion.

    .. important::
        Do not call directly, use :meth:`dataikuapi.dss.discussion.DSSObjectDiscussions.get_discussion`,
        :meth:`dataikuapi.dss.discussion.DSSObjectDiscussions.create_discussion`
        or :meth:`dataikuapi.dss.discussion.DSSObjectDiscussions.list_discussions`.
    """
    def __init__(self, client, project_key, object_type, object_id, discussion_id, discussion_data, discussion_data_has_replies):
        """
        :param :class:`dataikuapi.dssclient.DSSClient` client: an api client to connect to the DSS backend
        :param str project_key: identifier of the project to access
        :param str object_type: DSS object type
        :param str object_id: DSS object ID
        :param str discussion_id: identifier of the discussion
        :param dict discussion_data: the discussion data
        :param bool discussion_data_has_replies: a flag that indicates if the replies has been loaded
        """
        self.client = client
        self.project_key = project_key
        self.object_type = object_type
        self.object_id = object_id
        self.discussion_id = discussion_id
        self.discussion_data = discussion_data
        self.discussion_data_has_replies = discussion_data_has_replies

    def _get_with_replies(self):
        """
        Reloads the discussion data from the backend including the replies.
        """
        self.discussion_data = self.client._perform_json("GET", "/projects/%s/discussions/%s/%s/%s" % (self.project_key, self.object_type, self.object_id, self.discussion_id))
        self.discussion_data_has_replies = True

    def get_metadata(self):
        """
        Gets the discussion metadata.

        :returns: the discussion metadata
        :rtype: dict
        """
        metadata = dict(self.discussion_data)
        if "replies" in metadata:
            del metadata["replies"]
        return metadata

    def set_metadata(self, discussion_metadata):
        """
        Updates the discussion metadata.

        :param dict discussion_metadata: the discussion metadata
        """
        if not self.discussion_data_has_replies:
            self._get_with_replies()

        edited_metadata = dict(discussion_metadata)
        edited_metadata["replies"] = self.discussion_data["replies"]

        self.discussion_data = self.client._perform_json("PUT", "/projects/%s/discussions/%s/%s/%s" % (self.project_key, self.object_type, self.object_id, self.discussion_id), body=edited_metadata)
        self.discussion_data_has_replies = True

    def get_replies(self):
        """
        Gets the list of replies in this discussion.

        :returns: a list of replies
        :rtype: list of :class:`dataikuapi.dss.discussion.DSSDiscussionReply`
        """
        if not self.discussion_data_has_replies:
            self._get_with_replies()

        return [DSSDiscussionReply(reply_data) for reply_data in self.discussion_data["replies"]]

    def add_reply(self, text):
        """
        Adds a reply to a discussion.

        :param str text: the markdown formatted text to reply
        """
        reply_data = {
            "reply": text
        }
        self.discussion_data = self.client._perform_json("POST", "/projects/%s/discussions/%s/%s/%s/replies/" % (self.project_key, self.object_type, self.object_id, self.discussion_id), body=reply_data)
        self.discussion_data_has_replies = True

class DSSDiscussionReply(object):
    """
    A read-only handle to access a discussion reply.

    .. important::
        Do not create this class directly, use :meth:`dataikuapi.dss.discussion.DSSDiscussion.get_replies`
    """
    def __init__(self, reply_data):
        self.reply_data = reply_data

    def get_raw_data(self):
        """
        Gets the reply raw data.

        :returns: the reply data
        :rtype: dict
        """
        return self.reply_data

    def get_text(self):
        """
        Gets the reply text.

        :returns: the reply text
        :rtype: str
        """
        return self.reply_data["text"]

    def get_author(self):
        """
        Gets the reply author.

        :returns: the author ID
        :rtype: str
        """
        return self.reply_data["author"]

    def get_timestamp(self):
        """
        Gets the reply timestamp.

        :returns: the reply timestamp
        :rtype: long
        """
        return self.reply_data["time"]

    def get_edited_timestamp(self):
        """
        Gets the last edition timestamp.

        :returns: the last edition timestamp
        :rtype: long
        """
        return self.reply_data["editedOn"]
