#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#  Licensed under the Apache License, Version 2.0 (the "License");
#  you may not use this file except in compliance with the License.
#  You may obtain a copy of the License at
#
#    http://www.apache.org/licenses/LICENSE-2.0
#
#  Unless required by applicable law or agreed to in writing, software
#  distributed under the License is distributed on an "AS IS" BASIS,
#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#  See the License for the specific language governing permissions and
#  limitations under the License.

from datetime import datetime
from jira_github import Jira
from .formatter import Formatter


def daydiff(a, b):
    return (a - b).days


class Report:
    now = datetime.utcnow()

    def __init__(self, header=''):
        self.header = header

    # if padding starts with - it puts padding before contents, otherwise after
    @staticmethod
    def _build_tuple(contents, padding=''):
        if padding:
            out = []
            for i in range(len(contents)):
                out += [padding[1:] + str(contents[i])] if padding[0] == '-' else [str(contents[i]) + padding]
            return tuple(out)
        return contents

    # calls the native print function with the following format. Text1,Text2,... has the correct spacing
    # print("%s%s%s" % ("Text1, Text2, Text3))
    def print_(self, formatter, row_tuple):
        print(formatter.format % formatter.row_str_format(row_tuple))


class JiraReport(Report):
    def __init__(self, issues, header=''):
        Report.__init__(self, header)
        self.issues = issues

    def view(self, excluded):
        issues_view = dict(self.issues)
        for key in excluded:
            issues_view.pop(key, None)
        return issues_view

    def keys_view(self, excluded):
        return self.view(excluded).keys().sort(Jira.storm_jira_cmp, reverse=True)

    def values_view(self, excluded=None):
        temp_dic = dict(self.issues) if excluded is None else self.view(excluded)
        return sorted(temp_dic.values(), key=lambda jira: jira.get_id_num(), reverse=True)

    @staticmethod
    def _row_tuple(jira):
        return (jira.get_id(), jira.get_trimmed_summary(), daydiff(Report.now, jira.get_created()),
                daydiff(Report.now, jira.get_updated()))

    def _min_width_tuple(self):
        return -1, 43, -1, -1

    def print_report(self):
        print(f"{self.header} (Count = {len(self.issues)}) ")
        jiras = self.values_view()
        fields_tuple = ('Jira Id', 'Summary', 'Created', 'Last Updated (Days)')
        row_tuple = self._row_tuple(jiras[0])

        formatter = Formatter(fields_tuple, row_tuple, self._min_width_tuple())

        self.print_(formatter, fields_tuple)

        for jira in jiras:
            row_tuple = self._row_tuple(jira)
            self.print_(formatter, row_tuple)

    @staticmethod
    def build_jira_url(jira_id):
        BASE_URL = "https://issues.apache.org/jira/browse/"
        return BASE_URL + jira_id


class GitHubReport(Report):
    def __init__(self, pull_requests=None, header=''):
        Report.__init__(self, header)

        if pull_requests is None:
            self.pull_requests = []
            self.type = ''
        else:
            self.pull_requests = pull_requests
            self.type = type

    def _row_tuple(self, pull):
        return self._build_tuple(
            (pull.html_url(), pull.trimmed_title(), daydiff(Report.now, pull.created_at()),
             daydiff(Report.now, pull.updated_at()), pull.user()), '')

    def _min_width_tuple(self):
        return -1, 43, -1, -1, -1

    def print_report(self):
        print("%s (Count = %s) " % (self.header, len(self.pull_requests)))

        fields_tuple = self._build_tuple(('URL', 'Title', 'Created', 'Last Updated (Days)', 'User'), '')
        if len(self.pull_requests) > 0:
            row_tuple = self._row_tuple(self.pull_requests[0])

            formatter = Formatter(fields_tuple, row_tuple, self._min_width_tuple())

            self.print_(formatter, fields_tuple)
            for pull in self.pull_requests:
                row_tuple = self._row_tuple(pull)
                self.print_(formatter, row_tuple)

    def jira_ids(self):
        """
        :return: sorted list of JIRA ids present in Git pull requests
        """
        jira_ids = list()
        for pull in self.pull_requests:
            jira_ids.append(pull.jira_id())
        return sorted(jira_ids)


class JiraGitHubCombinedReport(Report):
    def __init__(self, jira_report, github_report, header='', print_comments=False):
        Report.__init__(self, header)
        self.jira_report = jira_report
        self.github_report = github_report
        self.print_comments = print_comments

    def _jira_comments(self, jira_id):
        return None if jira_id is None else self.jira_report.issues[jira_id].get_comments()

    def _idx_1st_comment_with_vote(self):
        g = 0
        for pull in self.github_report.pull_requests:
            c = 0
            for comment in self._jira_comments(pull.jira_id()):
                if comment.has_vote():
                    return(g,) + (c,)
                c += 1
            g += 1

    def _pull_request(self, pull_idx):
        pull = self.github_report.pull_requests[pull_idx]
        return pull

    def _jira_id(self, pull_idx):
        pull = self._pull_request(pull_idx)
        return str(pull.jira_id())

    def _jira_issue(self, jira_id):
        return self.jira_report.issues[jira_id]

    def _row_tuple(self, pull_idx):
        pull = self._pull_request(pull_idx)
        jira_id = self._jira_id(pull_idx)
        jira_issue = self._jira_issue(jira_id)

        return (jira_id, str(pull) if pull else "No PR", jira_issue.get_trimmed_summary(),
                daydiff(Report.now, jira_issue.get_created()),
                daydiff(Report.now, pull.created_at() if pull else "No PR"),
                daydiff(Report.now, jira_issue.get_updated()),
                daydiff(Report.now, pull.updated_at() if pull else "No PR"),
                jira_issue.get_status(), pull.user())

    def _row_tuple_1(self, pull_idx, comment_idx):
        row_tuple_1 = None
        jira_id = self._jira_id(pull_idx)
        jira_comments = self._jira_comments(jira_id)
        comment = jira_comments[comment_idx]
        if comment.has_vote():
            row_tuple_1 = (comment.get_vote(), comment.get_author(), comment.get_pull(),
                           daydiff(Report.now, comment.get_created()))

        return row_tuple_1

    # variables and method names ending with _1 correspond to the comments part
    def print_report(self, print_comments=False):
        pull_request_cnt = len(self.github_report.pull_requests)
        print("%s (Count = %s) " % (self.header, pull_request_cnt))
        if not pull_request_cnt:
            return

        fields_tuple = ('JIRA ID', 'Pull Request', 'Jira Summary', 'JIRA Age',
                        'Pull Age', 'JIRA Update Age', 'Pull Update Age (Days)',
                        'JIRA Status', 'GitHub user')
        row_tuple = self._row_tuple(0)
        formatter = Formatter(fields_tuple, row_tuple)
        self.print_(formatter, fields_tuple)

        if print_comments or self.print_comments:
            fields_tuple_1 = self._build_tuple(('Comment Vote', 'Comment Author', 'Pull URL', 'Comment Age'), '-\t\t')
            row_tuple_1 = self._build_tuple(self._row_tuple_1(*self._idx_1st_comment_with_vote()), '-\t\t')
            formatter_1 = Formatter(fields_tuple_1, row_tuple_1)
            self.print_(formatter_1, fields_tuple_1)
            print('')

        for p in range(0, len(self.github_report.pull_requests)):
            row_tuple = self._row_tuple(p)
            self.print_(formatter, row_tuple)

            if print_comments or self.print_comments:
                has_vote = False
                comments = self._jira_comments(self._jira_id(p))
                for c in range(len(comments)):     # Check cleaner way
                    comment = comments[c]
                    if comment.has_vote():
                        row_tuple_1 = self._build_tuple(self._row_tuple_1(p, c), '-\t\t')
                        if row_tuple_1 is not None:
                            formatter_1 = Formatter()
                            self.print_(formatter_1, row_tuple_1)
                            has_vote = True
                if has_vote:
                    print('')


class CompleteReport(Report):
    def __init__(self, header=''):
        Report.__init__(self, header)
        self.jira_reports = []
        self.github_reports = []
        self.jira_github_combined_reports = []

    def print_all(self):
        if self.header:
            print(self.header)

        self._print_github_reports()
        self._print_jira_github_combined_reports()
        self._print_jira_reports()

    def _print_jira_reports(self):
        for jira in self.jira_reports:
            jira.print_report()

    def _print_github_reports(self):
        for github in self.github_reports:
            github.print_report()

    def _print_jira_github_combined_reports(self):
        for jira_github_combined in self.jira_github_combined_reports:
            jira_github_combined.print_report()
