import os
from os.path import normpath, join

from reportlab.lib.colors import HexColor
from reportlab.lib.pagesizes import landscape, letter
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
from reportlab.pdfgen import canvas

from app.main.data_model.games.pv_challenge_officine.pv_challenge_officine_challenge import PVChallengeOfficineChallenge
from app.main.data_model.games.pv_challenge_officine.pv_challenge_officine_challenge_badge import PVChallengeOfficineChallengeBadge
from app.main.data_model.games.pv_challenge_officine.pv_challenge_officine_challenge_day import PVChallengeOfficineChallengeDay
from app.main.data_model.games.pv_challenge_officine.pv_challenge_officine_challenge_decision import PVChallengeOfficineChallengeDecision
from app.main.data_model.games.pv_challenge_officine.pv_challenge_officine_challenge_decision_details import PVChallengeOfficineChallengeDecisionDetails
from app.main.data_model.games.pv_challenge_officine.pv_challenge_officine_challenge_story_steps import PVChallengeOfficineChallengeStorySteps
from app.main.util.json_objects.games.pv_challenge_officine.pv_challenge_officine_day_dto import PVChallengeOfficineDayDTO
from app.main.util.json_objects.games.pv_challenge_officine.pv_challenge_officine_decision_details_dto import PVChallengeOfficineDecisionDetailsDTO
from app.main.util.json_objects.games.pv_challenge_officine.pv_challenge_officine_challenge_dto import PVChallengeOfficineChallengeDTO
from app.main.util.json_objects.games.pv_challenge_officine.pv_challenge_officine_score_dto import PVChallengeOfficineScoreDTO


class PVChallengeOfficineServiceHelper:

    def __init__(self):
        pass

    @staticmethod
    def update_challenge(challenge, challenge_data):
        name = challenge_data['name']
        avatar_id = challenge_data['avatar_id']
        fonction = challenge_data['fonction']
        challenge.name = name
        challenge.avatar_id = avatar_id
        challenge.fonction = fonction

    @staticmethod
    def create_challenge_dto(challenge, type_contrat):
        challenge_dto = PVChallengeOfficineChallengeDTO()
        challenge_dto.init(challenge)
        challenge_dto.type_contrat = type_contrat
        return challenge_dto

    @staticmethod
    def create_challenge_decisions(decisions_data, old_decisions):
        challenge_id = decisions_data['challenge_id']
        day_id = decisions_data['day_id']
        decision_ids = decisions_data['decisions']
        pv_challenge_decisions = []
        old_decision_ids = []
        decision_ids_to_delete = []
        if old_decisions is not None:
            old_decision_ids = [decision.decision_id for decision in old_decisions]
            decision_ids_to_delete = [old_decision_id for old_decision_id in old_decision_ids if old_decision_id
                                      not in decision_ids]
        for decision_id in decision_ids:
            if decision_id in old_decision_ids:
                continue
            pv_challenge_challenge_decision = PVChallengeOfficineChallengeDecision(challenge_id, decision_id, day_id)
            pv_challenge_decisions.append(pv_challenge_challenge_decision)
        return pv_challenge_decisions, decision_ids_to_delete

    @staticmethod
    def create_challenge_decision_details(decision_details_data, pv_challenge_old_decision_details):
        challenge_id = decision_details_data['challenge_id']
        day_id = decision_details_data['day_id']
        details = decision_details_data['details']
        if pv_challenge_old_decision_details is None:
            pv_challenge_decision_details = PVChallengeOfficineChallengeDecisionDetails(challenge_id, day_id, details)
            return pv_challenge_decision_details
        else:
            pv_challenge_old_decision_details.details = details
            return pv_challenge_old_decision_details

    @staticmethod
    def create_decision_scores_dto(decision_scores):
        if decision_scores is None or len(decision_scores) == 0:
            return {'score1': 0.0, 'score2': 0.0}
        score1, score2 = 0, 0
        if decision_scores[0][1] is not None:
            score1 = decision_scores[0][1]
        if decision_scores[0][2] is not None:
            score2 = decision_scores[0][2]
        return {'score1': int(score1), 'score2': int(score2)}

    @staticmethod
    def create_challenge_scores_dto(challenge_scores):
        if challenge_scores is None or len(challenge_scores) == 0:
            return {}
        score1, score2 = 0, 0
        if challenge_scores[0][0] is not None:
            score1 = challenge_scores[0][0]
        if challenge_scores[0][1] is not None:
            score2 = challenge_scores[0][1]
        return {'score1': int(score1), 'score2': int(score2)}

    @staticmethod
    def create_pv_challenge_officine_challenge(game_session_id, participant_id):
        pv_challenge_challenge = PVChallengeOfficineChallenge('Mon Challenge', 'Participant', game_session_id, participant_id)
        return pv_challenge_challenge


    @staticmethod
    def create_scores_dtos(pv_challenges, scores):
        scores_dtos = {}
        if pv_challenges is None:
            pv_challenges = []
        for challenge in pv_challenges:
            pv_challenge_dto = PVChallengeOfficineServiceHelper.create_challenge_dto(challenge, None)
            pv_score_dto = PVChallengeOfficineScoreDTO()
            pv_score_dto.pv_challenge_officine = pv_challenge_dto
            scores_dtos[challenge.id] = pv_score_dto
        if scores is None or len(scores) == 0:
            return list(scores_dtos.values())
        for row in scores:
            challenge_id = int(row[0])
            if challenge_id not in scores_dtos:
                continue
            pv_score_dto = scores_dtos[challenge_id]
            pv_score_dto.score1 = int(row[1])
            pv_score_dto.score2 = int(row[2])
        return list(scores_dtos.values())

    @staticmethod
    def create_challenge_day(challenge_id, day_id):
        pv_challenge_challenge_day = PVChallengeOfficineChallengeDay(0, 0,  0, -1, challenge_id, day_id)
        return pv_challenge_challenge_day

    @staticmethod
    def create_challenge_badges_dtos(challenge_badges):
        challenge_badges_dtos = []
        if challenge_badges is None:
            return challenge_badges_dtos
        for challenge_badge in challenge_badges:
            challenge_badge_dto = {'id': challenge_badge.id, 'badge_id': challenge_badge.badge_id,
                                 'challenge_id': challenge_badge.challenge_id, 'status': challenge_badge.status}
            challenge_badges_dtos.append(challenge_badge_dto)
        return challenge_badges_dtos

    @staticmethod
    def create_pv_challenge_officine_challenge_badges(participant_challenge, pv_challenge_badges):
        pv_challenge_challenge_badges = []
        for pv_challenge_badge in pv_challenge_badges:
            pv_challene_challenge_badge = PVChallengeOfficineChallengeBadge(participant_challenge.id, pv_challenge_badge.id, 0)
            pv_challenge_challenge_badges.append(pv_challene_challenge_badge)
        return pv_challenge_challenge_badges

    @staticmethod
    def create_pv_challenge_officine_challenge_days(participant_challenge, pv_challenge_days):
        pv_challenge_challenge_days = []
        first_day = None
        for pv_challenge_day in pv_challenge_days:
            pv_challenge_challenge_day = PVChallengeOfficineChallengeDay(0, 0, 0, -1, participant_challenge.id, pv_challenge_day.id)
            if pv_challenge_day.id == 1:
                first_day = pv_challenge_challenge_day
            pv_challenge_challenge_days.append(pv_challenge_challenge_day)
        first_day.status = 0
        first_day.set_start_date()
        return pv_challenge_challenge_days

    @staticmethod
    def create_days_dtos(challenge_days, challenge_decisions):
        day_dtos = {}
        for challenge_day in challenge_days:
            day_dto = PVChallengeOfficineDayDTO()
            day_dto.id = challenge_day.id
            day_dto.day_id = challenge_day.day_id
            day_dto.status = challenge_day.status
            day_dto.stars = challenge_day.stars
            day_dto.score1 = challenge_day.score1
            day_dto.score2 = challenge_day.score2
            day_dto.decisions = []
            day_dtos[day_dto.day_id] = day_dto
        if challenge_decisions is not None:
            for challenge_decision in challenge_decisions:
                day_id = challenge_decision.day_id
                if day_id not in day_dtos:
                    continue
                day_dto = day_dtos[day_id]
                day_dto.decisions.append(challenge_decision.decision_id)
        return list(day_dtos.values())

    @staticmethod
    def create_challenge_decision_details_dtos(pv_challenge_decision_details):
        decision_details_dtos = []
        for decision_details in pv_challenge_decision_details:
            decision_details_dto = PVChallengeOfficineDecisionDetailsDTO()
            decision_details_dto.id = decision_details.id
            decision_details_dto.challenge_id = decision_details.challenge_id
            decision_details_dto.day_id = decision_details.day_id
            decision_details_dto.details = decision_details.details
            decision_details_dtos.append(decision_details_dto)
        return decision_details_dtos

    @staticmethod
    def create_closing_day_dto(pv_challenge_day, challenge_badges_dtos, success):
        return {'challenge_id': pv_challenge_day.challenge_id, 'day_id': pv_challenge_day.day_id, 'stars': pv_challenge_day.stars,
                'score1': pv_challenge_day.score1, 'score2': pv_challenge_day.score2,
                'badges': challenge_badges_dtos, 'success': success}

    @staticmethod
    def create_not_closing_day_dto(pv_challenge_day):
        return {'challenge_id': pv_challenge_day.challenge_id, 'day_id': pv_challenge_day.day_id, 'stars': pv_challenge_day.stars,
                'score1': pv_challenge_day.score1, 'score2': pv_challenge_day.score2,
                'badges': [], 'success': False}

    @staticmethod
    def create_day1_story_steps(pv_challenge_challenge_day, pv_decision_repository):
        challenge_id = pv_challenge_challenge_day.challenge_id
        quiz1 = int(pv_decision_repository.get_aggregated_decision_scores([i for i in range(1, 9)], challenge_id)[0][0])
        quiz2 = int(pv_decision_repository.get_aggregated_decision_scores([i for i in range(9, 21)], challenge_id)[0][0])
        drag_and_drop = int(pv_decision_repository.get_aggregated_decision_scores([i for i in range(21, 36)], challenge_id)[0][0])

        story_steps = [PVChallengeOfficineChallengeStorySteps(1, challenge_id, quiz1, 0, ""),
                       PVChallengeOfficineChallengeStorySteps(2, challenge_id, quiz2, 0, ""),
                       PVChallengeOfficineChallengeStorySteps(3, challenge_id, drag_and_drop, 0, ""),
                       PVChallengeOfficineChallengeStorySteps(4, challenge_id, quiz1 + quiz2 + drag_and_drop, 0, "")]
        return story_steps

    @staticmethod
    def create_day2_story_steps(pv_challenge_challenge_day, pv_decision_repository):
        challenge_id = pv_challenge_challenge_day.challenge_id
        quiz1 = int(pv_decision_repository.get_aggregated_decision_scores([i for i in range(36, 41)], challenge_id)[0][0])
        drag_and_drop = int(pv_decision_repository.get_aggregated_decision_scores([i for i in range(41, 56)], challenge_id)[0][0])
        activite =int(pv_decision_repository.get_aggregated_decision_scores([i for i in range(56, 63)], challenge_id)[0][0])
        quiz2 = int(pv_decision_repository.get_aggregated_decision_scores([i for i in range(63, 69)], challenge_id)[0][0])

        story_steps = [PVChallengeOfficineChallengeStorySteps(5, challenge_id, quiz1, 0, ""),
                       PVChallengeOfficineChallengeStorySteps(6, challenge_id, drag_and_drop, 0, ""),
                       PVChallengeOfficineChallengeStorySteps(7, challenge_id, activite, 0, ""),
                       PVChallengeOfficineChallengeStorySteps(8, challenge_id, quiz2, 0, ""),
                       PVChallengeOfficineChallengeStorySteps(9, challenge_id, quiz1 + drag_and_drop + activite + quiz2 , 0, "")]
        return story_steps

    @staticmethod
    def create_day3_story_steps(pv_challenge_challenge_day, pv_decision_repository):
        challenge_id = pv_challenge_challenge_day.challenge_id
        choix_1 = int(pv_decision_repository.get_aggregated_decision_scores([i for i in range(69, 83)], challenge_id)[0][0])
        fiche = int(pv_decision_repository.get_aggregated_decision_scores([i for i in range(83, 95)], challenge_id)[0][1])
        quiz_1 = int(pv_decision_repository.get_aggregated_decision_scores([i for i in range(95, 99)], challenge_id)[0][0])
        choix_2 = pv_decision_repository.get_aggregated_decision_scores([i for i in range(99, 112)], challenge_id)
        choix_2_0 = int(choix_2[0][0])
        choix2_1 = int(choix_2[0][1])
        quiz_2 = int(pv_decision_repository.get_aggregated_decision_scores([i for i in range(112, 117)], challenge_id)[0][1])

        story_steps = [PVChallengeOfficineChallengeStorySteps(10, challenge_id, choix_1, 0, ""),
                       PVChallengeOfficineChallengeStorySteps(11, challenge_id, fiche, 0, ""),
                       PVChallengeOfficineChallengeStorySteps(12, challenge_id, quiz_1, 0, ""),
                       PVChallengeOfficineChallengeStorySteps(13, challenge_id, choix_2_0, choix2_1, ""),
                       PVChallengeOfficineChallengeStorySteps(14, challenge_id, quiz_2, 0, ""),
                       PVChallengeOfficineChallengeStorySteps(15, challenge_id, choix_1 + quiz_1 + choix_2_0, fiche + choix2_1 + quiz_2, "")]
        return story_steps

    @staticmethod
    def create_day4_story_steps(pv_challenge_challenge_day, pv_decision_repository):
        challenge_id = pv_challenge_challenge_day.challenge_id
        notification_tel = int(pv_decision_repository.get_aggregated_decision_scores([i for i in range(117, 129)], challenge_id)[0][1])
        notification_email = int(pv_decision_repository.get_aggregated_decision_scores([i for i in range(129, 143)], challenge_id)[0][1])
        notification_papier = int(pv_decision_repository.get_aggregated_decision_scores([i for i in range(143, 153)], challenge_id)[0][1])
        quiz = int(pv_decision_repository.get_aggregated_decision_scores([i for i in range(153, 156)], challenge_id)[0][1])

        story_steps = [PVChallengeOfficineChallengeStorySteps(16, challenge_id, notification_tel, 0, ""),
                       PVChallengeOfficineChallengeStorySteps(17, challenge_id, notification_email, 0, ""),
                       PVChallengeOfficineChallengeStorySteps(18, challenge_id, notification_papier, 0, ""),
                       PVChallengeOfficineChallengeStorySteps(19, challenge_id, quiz, 0, ""),
                       PVChallengeOfficineChallengeStorySteps(20, challenge_id, notification_tel + notification_email + notification_papier + quiz,
                                            0, "")]
        return story_steps

    @staticmethod
    def create_day5_story_steps(pv_challenge_challenge_day, pv_decision_repository):
        challenge_id = pv_challenge_challenge_day.challenge_id
        dossier_medecin = int(pv_decision_repository.get_aggregated_decision_scores([i for i in range(156, 166)], challenge_id)[0][1])
        dossier_delegue = int(
            pv_decision_repository.get_aggregated_decision_scores([i for i in range(166, 172)], challenge_id)[0][1])
        dossier_unite = int(
            pv_decision_repository.get_aggregated_decision_scores([i for i in range(172, 178)], challenge_id)[0][1])
        dossier_cnpv = int(
            pv_decision_repository.get_aggregated_decision_scores([i for i in range(178, 188)], challenge_id)[0][1])

        story_steps = [PVChallengeOfficineChallengeStorySteps(21, challenge_id, dossier_medecin, 0, ""),
                       PVChallengeOfficineChallengeStorySteps(22, challenge_id, dossier_delegue, 0, ""),
                       PVChallengeOfficineChallengeStorySteps(23, challenge_id, dossier_unite, 0, ""),
                       PVChallengeOfficineChallengeStorySteps(24, challenge_id, dossier_cnpv, 0, ""),
                       PVChallengeOfficineChallengeStorySteps(25, challenge_id, dossier_medecin + dossier_delegue +
                                                      dossier_unite + dossier_cnpv, 0, "")]
        return story_steps


    @staticmethod
    def create_challenge_story_steps_dtos(pv_challenge_story_steps):
        pv_challenge_story_steps_dtos = []
        for story_step in pv_challenge_story_steps:
            story_step_dto = {
                'challenge_id': story_step.challenge_id,
                'story_id': story_step.story_steps_id,
                'X': story_step.X,
                'Y': story_step.Y,
                'custom_message': story_step.custom_message
            }
            pv_challenge_story_steps_dtos.append(story_step_dto)
        return pv_challenge_story_steps_dtos

    @staticmethod
    def generate_certificate(full_name, certificat_number, expiry_date):
        attendee_name = full_name
        cwd = os.getcwd()
        file_name = full_name + "_"+certificat_number+ ".pdf"
        pdf_file_name = "app/main/util/certificat_files/pvchallenge_officine/"+file_name
        pdf_file_path = normpath(join(cwd, pdf_file_name))
        font_file_path = normpath(join(cwd, "app/main/util/certificat_files/SourceSerifPro-Bold.ttf"))
        layout_file_path = normpath(join(cwd, "app/main/util/certificat_files/layout_certificat_pv_challenge_officine.png"))
        pdfmetrics.registerFont(TTFont('Source Serif Pro Bold', font_file_path))
        c = canvas.Canvas(pdf_file_path, pagesize=landscape(letter))

        c.drawImage(layout_file_path, 0, 0, width=795, height=612)
        # attendee_name
        c.setFont('Source Serif Pro Bold', 26, leading=None)
        c.setFillColor(HexColor('#545454'))
        c.drawCentredString(int(795 / 2), 345, attendee_name.upper())

        # certificate number
        c.setFont('Source Serif Pro Bold', 13, leading=None)
        c.setFillColor(HexColor('#545454'))
        c.drawString(613, 142, certificat_number)
        # expiry date
        # c.setFont('Source Serif Pro Bold', 13, leading=None)
        # c.setFillColor(HexColor('#545454'))
        # c.drawString(613, 125, expiry_date.upper())
        c.showPage()
        c.save()
        return pdf_file_path, file_name



