from django.db import models
from django.shortcuts import get_object_or_404
from django.template import Template, Context
from django.utils.safestring import mark_safe

from .behaviors import validate_file_extension, validate_max_file_size

from commentaries.models import Commentary
from scipost.models import TimeStampedModel, Contributor
from submissions.models import Submission, Report
from theses.models import ThesisLink

COMMENT_CATEGORIES = (
    ('ERR', 'erratum'),
    ('REM', 'remark'),
    ('QUE', 'question'),
    ('ANS', 'answer to question'),
    ('OBJ', 'objection'),
    ('REP', 'reply to objection'),
    ('VAL', 'validation or rederivation'),
    ('LIT', 'pointer to related literature'),
    ('SUG', 'suggestion for further work'),
    )

COMMENT_STATUS = (
    (1, 'vetted'),
    (0, 'not yet vetted (pending)'),
    (-1, 'rejected (unclear)'),
    (-2, 'rejected (incorrect)'),
    (-3, 'rejected (not useful)'),
)
comment_status_dict = dict(COMMENT_STATUS)


class Comment(TimeStampedModel):
    """ A Comment is an unsollicited note, submitted by a Contributor,
    on a particular publication or in reply to an earlier Comment. """

    status = models.SmallIntegerField(default=0)
    vetted_by = models.ForeignKey(Contributor, blank=True, null=True,
                                  on_delete=models.CASCADE,
                                  related_name='comment_vetted_by')
    file_attachment = models.FileField(upload_to='comments/%Y/%m/%d/', blank=True,
                                       validators=[validate_file_extension,
                                                   validate_max_file_size])
    # a Comment is either for a Commentary or Submission or a ThesisLink.
    commentary = models.ForeignKey(Commentary, blank=True, null=True, on_delete=models.CASCADE)
    submission = models.ForeignKey(Submission, blank=True, null=True, on_delete=models.CASCADE)
    thesislink = models.ForeignKey(ThesisLink, blank=True, null=True, on_delete=models.CASCADE)
    is_author_reply = models.BooleanField(default=False)
    in_reply_to_comment = models.ForeignKey('self', blank=True, null=True,
                                            on_delete=models.CASCADE)
    in_reply_to_report = models.ForeignKey(Report, blank=True, null=True, on_delete=models.CASCADE)
    author = models.ForeignKey(Contributor, default=1, on_delete=models.CASCADE)
    anonymous = models.BooleanField(default=False, verbose_name='Publish anonymously')
    # Categories:
    is_cor = models.BooleanField(default=False, verbose_name='correction/erratum')
    is_rem = models.BooleanField(default=False, verbose_name='remark')
    is_que = models.BooleanField(default=False, verbose_name='question')
    is_ans = models.BooleanField(default=False, verbose_name='answer to question')
    is_obj = models.BooleanField(default=False, verbose_name='objection')
    is_rep = models.BooleanField(default=False, verbose_name='reply to objection')
    is_val = models.BooleanField(default=False, verbose_name='validation or rederivation')
    is_lit = models.BooleanField(default=False, verbose_name='pointer to related literature')
    is_sug = models.BooleanField(default=False, verbose_name='suggestion for further work')
    comment_text = models.TextField()
    remarks_for_editors = models.TextField(default='', blank=True,
                                           verbose_name='optional remarks for the Editors only')
    date_submitted = models.DateTimeField('date submitted')
    # Opinions
    nr_A = models.PositiveIntegerField(default=0)
    in_agreement = models.ManyToManyField(Contributor,
                                          related_name='in_agreement', blank=True)
    nr_N = models.PositiveIntegerField(default=0)
    in_notsure = models.ManyToManyField(Contributor,
                                        related_name='in_notsure', blank=True)
    nr_D = models.PositiveIntegerField(default=0)
    in_disagreement = models.ManyToManyField(Contributor,
                                             related_name='in_disagreement', blank=True)

    def __str__(self):
        return ('by ' + self.author.user.first_name + ' ' + self.author.user.last_name +
                ' on ' + self.date_submitted.strftime('%Y-%m-%d') + ', ' + self.comment_text[:30])

    def update_opinions(self, contributor_id, opinion):
        contributor = get_object_or_404(Contributor, pk=contributor_id)
        self.in_agreement.remove(contributor)
        self.in_notsure.remove(contributor)
        self.in_disagreement.remove(contributor)
        if opinion == 'A':
            self.in_agreement.add(contributor)
        elif opinion == 'N':
            self.in_notsure.add(contributor)
        elif opinion == 'D':
            self.in_disagreement.add(contributor)
        self.nr_A = self.in_agreement.count()
        self.nr_N = self.in_notsure.count()
        self.nr_D = self.in_disagreement.count()
        self.save()

    def opinions_as_ul(self):
        template = Template('''
        <ul class="opinionsDisplay">
        <li style="background-color: #000099">Agree {{ nr_A }}</li>
        <li style="background-color: #555555">Not sure {{ nr_N }}</li>
        <li style="background-color: #990000">Disagree {{ nr_D }}</li>
        </ul>
        ''')
        context = Context({'nr_A': self.nr_A, 'nr_N': self.nr_N, 'nr_D': self.nr_D})
        return template.render(context)

    def opinions_as_ul_tiny(self):
        template = Template('''
        <ul class="opinionsDisplay">
        <li style="background-color: #000099; font-size: 8px; padding: 2px;">Agree {{ nr_A }}</li>
        <li style="background-color: #555555; font-size: 8px; padding: 2px;">Not sure {{ nr_N }}</li>
        <li style="background-color: #990000; font-size: 8px; padding: 2px;">Disagree {{ nr_D }}</li>
        </ul>
        ''')
        context = Context({'nr_A': self.nr_A, 'nr_N': self.nr_N, 'nr_D': self.nr_D})
        return template.render(context)

    def print_identifier(self):
        # for display
        output = '<div class="commentid">\n'
        output += '<h3><a id="comment_id{{ id }}"></a>'
        context = Context({'id': self.id})
        if self.is_author_reply:
            output += 'Author '
        if not self.anonymous:
            output += (' <a href="/contributor/{{ author_id }}">'
                       + '{{ first_name }} {{ last_name }}</a> on ')
            context['author_id'] = self.author.id
            context['first_name'] = self.author.user.first_name
            context['last_name'] = self.author.user.last_name
        output += '{{ date_comment_submitted }}'
        context['date_comment_submitted'] = self.date_submitted.strftime("%Y-%m-%d")
        if self.in_reply_to_comment:
            output += (' (in reply to <a href="#comment_id{{ in_reply_to_comment_id }}">'
                       '{{ in_reply_to_comment_first_name }} '
                       '{{ in_reply_to_comment_last_name }} on '
                       '{{ in_reply_to_comment_date }}</a>)')
            context['in_reply_to_comment_id'] = self.in_reply_to_comment_id
            context['in_reply_to_comment_first_name'] = (self.in_reply_to_comment
                                                         .author.user.first_name)
            context['in_reply_to_comment_last_name'] = (self.in_reply_to_comment
                                                        .author.user.last_name)
            context['in_reply_to_comment_date'] = (self.in_reply_to_comment
                                                   .date_submitted.strftime("%Y-%m-%d"))
        elif self.in_reply_to_report:
            output += ' (in reply to <a href="#report_id{{ in_reply_to_report_id }}">'
            context['in_reply_to_report_id'] = self.in_reply_to_report_id
            if not self.in_reply_to_report.anonymous:
                output += '{{ in_reply_to_report_first_name }} {{ in_reply_to_report_last_name}}'
                context['in_reply_to_report_first_name'] = (self.in_reply_to_report
                                                            .author.user.first_name)
                context['in_reply_to_report_last_name'] = (self.in_reply_to_report
                                                           .author.user.last_name)
            else:
                output += 'Report {{ in_reply_to_report_id }}'
                context['in_reply_to_report_id'] = self.in_reply_to_report_id
            output += ' on {{ date_report_submitted }}</a>)'
            context['date_report_submitted'] = self.in_reply_to_report.date_submitted.strftime(
                                                                                        "%Y-%m-%d")
        output += '</h3></div>'
        template = Template(output)
        return template.render(context)

    def print_identifier_for_vetting(self):
        # for display, same as print_identifier but named even if anonymous, not linked
        output = '<div class="commentid">\n'
        output += '<h3>'
        context = Context()
        if self.is_author_reply:
            output += 'Author '
        output += ' <a href="/contributor/{{ author_id }}">{{ first_name }} {{ last_name }}</a>'
        context['author_id'] = self.author.id
        context['first_name'] = self.author.user.first_name
        context['last_name'] = self.author.user.last_name
        output += ' on {{ date_submitted }}'
        context['date_submitted'] = self.date_submitted.strftime("%Y-%m-%d")
        if self.in_reply_to_comment:
            output += (' (in reply to <a href="#comment_id{{ in_reply_to_comment_id }}">'
                       '{{ in_reply_to_comment_first_name }} {{ in_reply_to_comment_last_name }} '
                       'on {{ in_reply_to_comment_date }}</a>)')
            context['in_reply_to_comment_id'] = self.in_reply_to_comment_id
            context['in_reply_to_comment_first_name'] = (self.in_reply_to_comment
                                                         .author.user.first_name)
            context['in_reply_to_comment_last_name'] = (self.in_reply_to_comment
                                                        .author.user.last_name)
            context['in_reply_to_comment_date'] = (self.in_reply_to_comment
                                                   .date_submitted.strftime("%Y-%m-%d"))
        elif self.in_reply_to_report:
            output += ' (in reply to <a href="#report_id{{ in_reply_to_report_id }}">'
            context['in_reply_to_report_id'] = self.in_reply_to_report_id
            if not self.in_reply_to_report.anonymous:
                output += '{{ in_reply_to_report_first_name }} {{ in_reply_to_report_last_name}}'
                context['in_reply_to_report_first_name'] = (self.in_reply_to_report
                                                            .author.user.first_name)
                context['in_reply_to_report_last_name'] = (self.in_reply_to_report
                                                           .author.user.last_name)
            else:
                output += 'Report {{ in_reply_to_report_id }}'
                context['in_reply_to_report_id'] = self.in_reply_to_report_id
            output += '</a> on {{ date_submitted }})'
            context['date_submitted'] = self.in_reply_to_report.date_submitted.strftime("%Y-%m-%d")
        output += '</h3></div>'
        template = Template(output)
        return template.render(context)

    def header_as_li(self):
        # for search lists
        header = '<li>'
        # header += '<div class="flex-container"><div class="flex-whitebox0">'
        header += 'Nr {{ id }}'
        context = Context({'id': self.id})
        header += ', <div class="opinionsDisplay">' + self.opinions_as_ul_tiny() + '</div>'
        if self.status <= 0:
            header += (', status: <span style="color:red">'
                       + comment_status_dict[self.status] + '</span>')
        text_cut = self.comment_text[:50]
        if len(self.comment_text) > 50:
            text_cut += '...'
        context['id'] = self.id
        context['text_cut'] = text_cut
        context['date_submitted'] = self.date_submitted.strftime("%Y-%m-%d")
        header += ': '
        if not self.anonymous:
            header += (' <a href="/contributor/{{ author_id }}">'
                       '{{ first_name }} {{ last_name }}</a>, ')
            context['author_id'] = self.author.id
            context['first_name'] = self.author.user.first_name
            context['last_name'] = self.author.user.last_name
        if self.submission is not None:
            header += ('<a href="/submission/{{ arxiv_identifier_w_vn_nr }}#comment_id{{ id }}">'
                       ' \"{{ text_cut }}\"</a><p>submitted on {{ date_submitted }}')
            header += (' in submission on <a href="/submission/{{ arxiv_identifier_w_vn_nr }}"'
                       ' class="pubtitleli">{{ submission_title }}</a> by '
                       '{{ submission_author_list }}</p>')
            context['arxiv_identifier_w_vn_nr'] = self.submission.arxiv_identifier_w_vn_nr
            context['submission_title'] = self.submission.title
            context['submission_author_list'] = self.submission.author_list
        if self.commentary is not None:
            header += ('<a href="/commentary/{{ commentary_url }}#comment_id{{ id }}">'
                       ' \"{{ text_cut }}\"</a><p>submitted on {{ date_submitted }}')
            header += (' in commentary on <a href="/commentary/{{ commentary_url }}"'
                       ' class="pubtitleli">'
                       '{{ commentary_pub_title }}</a> by {{ commentary_author_list }}</p>')
            context['commentary_url'] = self.commentary.arxiv_or_DOI_string
            context['commentary_pub_title'] = self.commentary.pub_title
            context['commentary_author_list'] = self.commentary.author_list
        if self.thesislink is not None:
            header += ('<a href="/thesis/{{ thesislink_id }}#comment_id{{ id }}">'
                       ' \"{{ text_cut }}\"</a><p>submitted on {{ date_submitted }}')
            header += (' in thesislink on '
                       '<a href="/thesis/{{ thesislink_id }}" class="pubtitleli">'
                       '{{ thesislink_title }}</a> by {{ thesislink_author }}</p>')
            context['thesislink_id'] = self.thesislink.id
            context['thesislink_title'] = self.thesislink.title
            context['thesislink_author'] = self.thesislink.author
        # header += '</div></div>'
        header += '</li>'
        template = Template(header)
        return template.render(context)

    def simple_header_as_li(self):
        # for Lists
        header = '<li>'
        # header += '<div class="flex-container"><div class="flex-whitebox0">'
        context = Context({})
        text_cut = self.comment_text[:30]
        if len(self.comment_text) > 30:
            text_cut += '...'
        context['text_cut'] = text_cut
        if not self.anonymous:
            header += ' <a href="/contributor/{{ author_id }}">{{ first_name }} {{ last_name }}</a>, '
            context['author_id'] = self.author.id
            context['first_name'] = self.author.user.first_name
            context['last_name'] = self.author.user.last_name
        if self.submission is not None:
            header += ('<a href="/submission/{{ arxiv_identifier_w_vn_nr }}#comment_id{{ id }}"> '
                       '\"{{ text_cut }}\"</a>'
                       ' in submission on <a href="/submission/{{ arxiv_identifier_w_vn_nr }}" class="pubtitleli">'
                       '{{ submission_title }}</a> by {{ submission_author_list }}</p>')
            context['arxiv_identifier_w_vn_nr'] = self.submission.arxiv_identifier_w_vn_nr
            context['submission_title'] = self.submission.title
            context['submission_author_list'] = self.submission.author_list
        if self.commentary is not None:
            header += ('<a href="/commentary/{{ commentary_url }}#comment_id{{ id }}"> '
                       '\"{{ text_cut }}\"</a>'
                       ' in commentary on <a href="/commentary/{{ commentary_url }}" class="pubtitleli">'
                       '{{ commentary_pub_title }}</a> by {{ commentary_author_list }}</p>')
            context['commentary_url'] = self.commentary.arxiv_or_DOI_string
            context['commentary_pub_title'] = self.commentary.pub_title
            context['commentary_author_list'] = self.commentary.author_list
        if self.thesislink is not None:
            header += '<a href="/thesis/{{ thesislink_id }}#comment_id{{ id }}"> \"{{ text_cut }}\"</a>'
            header += (' in thesislink on '
                       '<a href="/thesis/{{ thesislink_id }}" class="pubtitleli">'
                       '{{ thesislink_title }}</a> by {{ thesislink_author }}</p>')
            context['thesislink_id'] = self.thesislink.id
            context['thesislink_title'] = self.thesislink.title
            context['thesislink_author'] = self.thesislink.author
        # header += '</div></div>'
        header += '</li>'
        template = Template(header)
        return template.render(context)

    def categories_as_ul(self):
        output = '<div class="commentcategorydisplay"><h4>Category:</h4><ul>'
        if self.is_rem:
            output += '<li>remark</li>'
        if self.is_que:
            output += '<li>question</li>'
        if self.is_ans:
            output += '<li>answer to question</li>'
        if self.is_obj:
            output += '<li>objection</li>'
        if self.is_rep:
            output += '<li>reply to objection</li>'
        if self.is_cor:
            output += '<li>correction</li>'
        if self.is_val:
            output += '<li>validation or rederivation</li>'
        if self.is_lit:
            output += '<li>pointer to related literature</li>'
        if self.is_sug:
            output += '<li>suggestion for further work</li>'
        output += '</ul></div>'
        return mark_safe(output)