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_pharma5.pv5_mission import PV5Mission
from app.main.data_model.games.pv_pharma5.pv5_mission_badge import PV5MissionBadge
from app.main.data_model.games.pv_pharma5.pv5_mission_day import PV5MissionDay
from app.main.data_model.games.pv_pharma5.pv5_mission_decision import PV5MissionDecision
from app.main.data_model.games.pv_pharma5.pv5_mission_decision_details import PV5MissionDecisionDetails
from app.main.data_model.games.pv_pharma5.pv5_mission_story_steps import PV5MissionStorySteps
from app.main.util.json_objects.games.pv5_game.pv5_day_dto import PV5DayDTO
from app.main.util.json_objects.games.pv5_game.pv5_decision_details_dto import PV5DecisionDetailsDTO
from app.main.util.json_objects.games.pv5_game.pv5_mission_dto import PV5MissionDTO
from app.main.util.json_objects.games.pv5_game.pv5_score_dto import PV5ScoreDTO


class PV5GameServiceHelper:

    def __init__(self):
        pass

    @staticmethod
    def update_mission(mission, mission_data):
        name = mission_data['name']
        avatar_id = mission_data['avatar_id']
        fonction = mission_data['fonction']
        mission.name = name
        mission.avatar_id = avatar_id
        mission.fonction = fonction

    @staticmethod
    def create_mission_dto(mission):
        mission_dto = PV5MissionDTO()
        mission_dto.init(mission)
        return mission_dto

    @staticmethod
    def create_mission_decisions(decisions_data, old_decisions):
        mission_id = decisions_data['mission_id']
        day_id = decisions_data['day_id']
        decision_ids = decisions_data['decisions']
        pv_mission_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_mission_decision = PV5MissionDecision(mission_id, decision_id, day_id)
            pv_mission_decisions.append(pv_mission_decision)
        return pv_mission_decisions, decision_ids_to_delete

    @staticmethod
    def create_mission_decision_details(decision_details_data, pv_mission_old_decision_details):
        mission_id = decision_details_data['mission_id']
        day_id = decision_details_data['day_id']
        details = decision_details_data['details']
        if pv_mission_old_decision_details is None:
            pv_mission_decision_details = PV5MissionDecisionDetails(mission_id, day_id, details)
            return pv_mission_decision_details
        else:
            pv_mission_old_decision_details.details = details
            return pv_mission_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_mission_scores_dto(mission_scores):
        if mission_scores is None or len(mission_scores) == 0:
            return {}
        score1, score2 = 0, 0
        if mission_scores[0][0] is not None:
            score1 = mission_scores[0][0]
        if mission_scores[0][1] is not None:
            score2 = mission_scores[0][1]
        return {'score1': int(score1), 'score2': int(score2)}

    @staticmethod
    def create_pv5_mission(game_session_id, participant_id):
        pv5_mission = PV5Mission('Ma mission', 'Participant', game_session_id, participant_id)
        return pv5_mission


    @staticmethod
    def create_scores_dtos(pv_missions, scores):
        scores_dtos = {}
        if pv_missions is None:
            pv_missions = []
        for mission in pv_missions:
            pv_mission_dto = PV5GameServiceHelper.create_mission_dto(mission)
            pv_score_dto = PV5ScoreDTO()
            pv_score_dto.pv_mission = pv_mission_dto
            scores_dtos[mission.id] = pv_score_dto
        if scores is None or len(scores) == 0:
            return list(scores_dtos.values())
        for row in scores:
            mission_id = int(row[0])
            if mission_id not in scores_dtos:
                continue
            pv_score_dto = scores_dtos[mission_id]
            pv_score_dto.score1 = int(row[1])
            pv_score_dto.score2 = int(row[2])
        return list(scores_dtos.values())

    @staticmethod
    def create_mission_day(mission_id, day_id):
        pv_mission_day = PV5MissionDay(0, 0,  0, -1, mission_id, day_id)
        return pv_mission_day

    @staticmethod
    def create_mission_badges_dtos(mission_badges):
        mission_badges_dtos = []
        if mission_badges is None:
            return mission_badges_dtos
        for mission_badge in mission_badges:
            mission_badges_dto = {'id': mission_badge.id, 'badge_id': mission_badge.badge_id,
                                 'mission_id': mission_badge.mission_id, 'status': mission_badge.status}
            mission_badges_dtos.append(mission_badges_dto)
        return mission_badges_dtos

    @staticmethod
    def create_pv5_mission_badges(participant_mission, pv5_badges):
        pv5_mission_badges = []
        for pv5_badge in pv5_badges:
            pv5_mission_badge = PV5MissionBadge(participant_mission.id, pv5_badge.id, 0)
            pv5_mission_badges.append(pv5_mission_badge)
        return pv5_mission_badges

    @staticmethod
    def create_pv5_mission_days(participant_mission, pv5_days):
        pv5_mission_days = []
        first_day = None
        for pv5_day in pv5_days:
            pv5_mission_day = PV5MissionDay(0, 0, 0, -1, participant_mission.id, pv5_day.id)
            if pv5_day.id == 1:
                first_day = pv5_mission_day
            pv5_mission_days.append(pv5_mission_day)
        first_day.status = 0
        first_day.set_start_date()
        return pv5_mission_days

    @staticmethod
    def create_days_dtos(mission_days, mission_decisions):
        day_dtos = {}
        for mission_day in mission_days:
            day_dto = PV5DayDTO()
            day_dto.id = mission_day.id
            day_dto.day_id = mission_day.day_id
            day_dto.status = mission_day.status
            day_dto.stars = mission_day.stars
            day_dto.score1 = mission_day.score1
            day_dto.score2 = mission_day.score2
            day_dto.decisions = []
            day_dtos[day_dto.day_id] = day_dto
        if mission_decisions is not None:
            for mission_decision in mission_decisions:
                day_id = mission_decision.day_id
                if day_id not in day_dtos:
                    continue
                day_dto = day_dtos[day_id]
                day_dto.decisions.append(mission_decision.decision_id)
        return list(day_dtos.values())

    @staticmethod
    def create_mission_decision_details_dtos(pv_mission_decision_details):
        decision_details_dtos = []
        for decision_details in pv_mission_decision_details:
            decision_details_dto = PV5DecisionDetailsDTO()
            decision_details_dto.id = decision_details.id
            decision_details_dto.mission_id = decision_details.mission_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_mission_day, mission_badges_dtos, success):
        return {'mission_id': pv_mission_day.mission_id, 'day_id': pv_mission_day.day_id, 'stars': pv_mission_day.stars,
                'score1': pv_mission_day.score1, 'score2': pv_mission_day.score2,
                'badges': mission_badges_dtos, 'success': success}

    @staticmethod
    def create_not_closing_day_dto(pv_mission_day):
        return {'mission_id': pv_mission_day.mission_id, 'day_id': pv_mission_day.day_id, 'stars': pv_mission_day.stars,
                'score1': pv_mission_day.score1, 'score2': pv_mission_day.score2,
                'badges': [], 'success': False}



    @staticmethod
    def create_day1_story_steps(pv_mission_day, pv_decision_repository):
        mission_id = pv_mission_day.mission_id
        quiz = int(pv_decision_repository.get_aggregated_decision_scores([i for i in range(1, 13)], mission_id)[0][0])
        drag_and_drop = int(pv_decision_repository.get_aggregated_decision_scores([i for i in range(13, 28)], mission_id)[0][0])

        story_steps = [PV5MissionStorySteps(1, mission_id, quiz, 0, ""),
                       PV5MissionStorySteps(2, mission_id, drag_and_drop, 0, ""),
                       PV5MissionStorySteps(3, mission_id, quiz + drag_and_drop, 0, "")]
        return story_steps

    @staticmethod
    def create_day2_story_steps(pv_mission_day, pv_decision_repository):
        mission_id = pv_mission_day.mission_id
        fiche_1 = int(pv_decision_repository.get_aggregated_decision_scores([i for i in range(28, 42)], mission_id)[0][0])
        fiche_2 = int(pv_decision_repository.get_aggregated_decision_scores([i for i in range(42, 54)], mission_id)[0][1])
        fiche_3_scores = pv_decision_repository.get_aggregated_decision_scores([i for i in range(54, 76)], mission_id)
        story_steps = [PV5MissionStorySteps(4, mission_id, fiche_1, 0, ""),
                       PV5MissionStorySteps(5, mission_id, fiche_2, 0, ""),
                       PV5MissionStorySteps(6, mission_id, int(fiche_3_scores[0][0]), int(fiche_3_scores[0][1]), ""),
                       PV5MissionStorySteps(7, mission_id, fiche_1 + int(fiche_3_scores[0][0]),
                                            fiche_2 + int(fiche_3_scores[0][1]), "")]
        return story_steps

    @staticmethod
    def create_day3_story_steps(pv_mission_day, pv_decision_repository):
        mission_id = pv_mission_day.mission_id
        day3_1 = int(pv_decision_repository.get_aggregated_decision_scores([i for i in range(76, 88)], mission_id)[0][1])
        day3_2 = int(pv_decision_repository.get_aggregated_decision_scores([i for i in range(88, 102)], mission_id)[0][1])
        day3_3 = int(pv_decision_repository.get_aggregated_decision_scores([i for i in range(102, 112)], mission_id)[0][1])
        day3_4 = int(pv_decision_repository.get_aggregated_decision_scores([i for i in range(112, 115)], mission_id)[0][1])
        total = day3_1 + day3_2 + day3_3 + day3_4
        story_steps = [PV5MissionStorySteps(8, mission_id, day3_1, 0, ""),
                       PV5MissionStorySteps(9, mission_id, day3_2, 0, ""),
                       PV5MissionStorySteps(10, mission_id, day3_3, 0, ""),
                       PV5MissionStorySteps(11, mission_id, day3_4, 0, ""),
                       PV5MissionStorySteps(12, mission_id, total, 0, "")]
        return story_steps

    @staticmethod
    def create_day4_story_steps(pv_mission_day, pv_decision_repository):
        mission_id = pv_mission_day.mission_id
        day4_1 = int(pv_decision_repository.get_aggregated_decision_scores([i for i in range(115, 122)], mission_id)[0][0])
        day4_2 = int(pv_decision_repository.get_aggregated_decision_scores([i for i in range(122, 130)], mission_id)[0][0])
        day_4_3 = int(pv_decision_repository.get_aggregated_decision_scores([i for i in range(130, 138)], mission_id)[0][0])
        day4_4 = int(pv_decision_repository.get_aggregated_decision_scores([i for i in range(138, 152)], mission_id)[0][1])

        story_steps = [PV5MissionStorySteps(13, mission_id, day4_1, 0, ""),
                       PV5MissionStorySteps(14, mission_id, day4_2, 0, ""),
                       PV5MissionStorySteps(15, mission_id, day_4_3, 0, ""),
                       PV5MissionStorySteps(16, mission_id, day4_4, 0, ""),
                       PV5MissionStorySteps(17, mission_id, day4_1 + day4_2 + day_4_3,
                                            day4_4, "")]
        return story_steps

    @staticmethod
    def create_day5_story_steps(pv_mission_day, pv_decision_repository):
        mission_id = pv_mission_day.mission_id
        day5_1 = int(pv_decision_repository.get_aggregated_decision_scores([i for i in range(152, 156)], mission_id)[0][0])
        day5_2 = int(pv_decision_repository.get_aggregated_decision_scores([i for i in range(156, 221)], mission_id)[0][1])
        story_steps = [PV5MissionStorySteps(18, mission_id, day5_1, 0, ""),
                       PV5MissionStorySteps(19, mission_id, day5_2, 0, ""),
                       PV5MissionStorySteps(20, mission_id, day5_1, day5_2, "")]
        return story_steps


    @staticmethod
    def create_mission_story_steps_dtos(pv_mission_story_steps):
        pv_mission_story_steps_dtos = []
        for story_step in pv_mission_story_steps:
            story_step_dto = {
                'mission_id': story_step.mission_id,
                'story_id': story_step.story_steps_id,
                'X': story_step.X,
                'Y': story_step.Y,
                'custom_message': story_step.custom_message
            }
            pv_mission_story_steps_dtos.append(story_step_dto)
        return pv_mission_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/"+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_pharma5.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('#00AABE'))
        c.drawCentredString(int(795 / 2), 350, attendee_name.upper())

        # certificate number
        c.setFont('Source Serif Pro Bold', 13, leading=None)
        c.setFillColor(HexColor('#404040'))
        c.drawString(613, 150, certificat_number)
        # expiry date
        c.setFont('Source Serif Pro Bold', 13, leading=None)
        c.setFillColor(HexColor('#404040'))
        c.drawString(613, 133, expiry_date.upper())
        c.showPage()
        c.save()
        return pdf_file_path, file_name



