from load.projects.tasklets.assessment.proto import assessment_tasklet
from .assessment import ShootingAssessment, AssessmentError
from tasklet.services.yav.proto import yav_pb2
import json
import requests
import re
import logging


class AssessmentImpl(assessment_tasklet.AssessmentBase):
    def run(self):
        if not self.input.shooting.shooting_id or not self.input.conditions.reference or len(self.input.conditions.reference) == 0:
            raise AssessmentError("Wrong input parameters!")
        if not self.input.conditions.threshold:
            self.input.conditions.threshold = 5

        self.assessment = ShootingAssessment(shooting_id=self.input.shooting.shooting_id, reference_list=self.input.conditions.reference, assessment_tests=self.input.conditions.tests)
        self.output.assessment.result = json.dumps(self.assessment.result)
        self.output.assessment.link = self.assessment.get_link(len(self.input.conditions.reference) + 1)

        assessments_failed = []
        for assessment_name, relative in self.assessment.result.items():
            if relative >= self.input.conditions.threshold/100:
                assessments_failed.append(assessment_name)
        self.status = len(assessments_failed) == 0

        if self.input.conditions.st_token:
            token = self.ctx.yav.get_secret(yav_pb2.YavSecretSpec(uuid=self.input.context.secret_uid, key=self.input.conditions.st_token)).secret
            if token and self.input.conditions.ticket:
                send_comment_in_startrek(token, self.input.conditions.ticket, self.make_report())

        if assessments_failed:
            raise AssessmentError(f'Assessments failed: {assessments_failed}. '
                                  'Base value was exceeded more(or equal) '
                                  f'than {self.input.conditions.threshold} percent.')

    def make_report(self):
        HEADER = "Assessment of the ((https://lunapark.yandex-team.ru/{} shooting)) is !!({}){}!!\n#|"
        FOOTER = "|#\n(({} Comparison page))"
        COLORS = {0: "red", 1: "green", 2: "yellow"}
        STATUS = {0: "FAILED", 1: "PASSED"}

        report = [HEADER.format(self.input.shooting.shooting_id, COLORS[self.status], STATUS[self.status])]
        for key, value in self.assessment.result.items():
            if re.match(r'^quantile.', key):
                report.append("||!!({}){}!!|{}||".format(
                    COLORS[check_quantile(value, self.input.conditions.threshold/100)],
                    key,
                    get_quantile_comment(value, self.assessment.percentiles[key.strip("quantile")])
                ))
            if re.match(r'^[a-x]*.codes$', key):
                report.append("||!!({}){}!!||\n||{}||".format(
                    COLORS[value <= self.input.conditions.threshold/100],
                    key,
                    get_codes_comment(self.assessment.codes[key.strip("_codes")]),
                ))
        report.append(FOOTER.format(self.output.assessment.link))
        return "\n".join(report)


def check_quantile(relative, threshold):
    if relative < 0:
        return 2
    elif relative >= 0 and relative <= threshold:
        return 1
    else:
        return 0


def get_quantile_comment(relative, qtime):
    try:
        reference = qtime / (1 + relative)
        delay = reference * relative
        if delay <= 0:
            return "reference|{:1.2f} ms|result|{:1.2f}ms ({:1.2f} ms)".format(reference, qtime, delay)
        else:
            return "reference|{:1.2f} ms|result|{:1.2f}ms (+{:1.2f} ms)".format(reference, qtime, delay)
    except ValueError:
        return None


def get_codes_comment(codes):
    if isinstance(codes, dict):
        return "|".join(["'{}'|{:1.2f}%".format(key, float(value)) for key, value in codes.items()])
    else:
        return None


def send_comment_in_startrek(token, ticket, comment):
    URL = "https://st-api.yandex-team.ru/v2/issues/{}/comments".format(ticket)
    DATA = {"text": comment}
    HEADERS = {"Authorization": "OAuth {}".format(token), "Content-Type": "application/json"}
    try:
        requests.post(url=URL, headers=HEADERS, data=json.dumps(DATA))
    except (requests.RequestException, ValueError) as error:
        logging.error("Comment error: {}".format(error))
