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.p2p_game.p2p_game_mission import P2pGameMission
from app.main.data_model.games.p2p_game.p2p_game_mission_badge import P2pGameMissionBadge
from app.main.data_model.games.p2p_game.p2p_game_mission_day import P2pGameMissionDay
from app.main.data_model.games.p2p_game.p2p_game_mission_decision import P2pGameMissionDecision
from app.main.data_model.games.p2p_game.p2p_game_mission_decision_details import P2pGameMissionDecisionDetails
from app.main.data_model.games.p2p_game.p2p_game_mission_story_steps import P2pGameMissionStorySteps
from app.main.util.json_objects.games.p2p_game.p2p_game_day_dto import P2pGameDayDTO
from app.main.util.json_objects.games.p2p_game.p2p_game_decision_details_dto import P2pGameDecisionDetailsDTO
from app.main.util.json_objects.games.p2p_game.p2p_game_mission_dto import P2pGameMissionDTO
from app.main.util.json_objects.games.p2p_game.p2p_game_score_dto import P2pGameScoreDTO


class P2pGameGameServiceHelper:

    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 = P2pGameMissionDTO()
        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']
        p2p_game_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
            p2p_game_mission_decision = P2pGameMissionDecision(mission_id, decision_id, day_id)
            p2p_game_mission_decisions.append(p2p_game_mission_decision)
        return p2p_game_mission_decisions, decision_ids_to_delete

    @staticmethod
    def create_mission_decision_details(decision_details_data, p2p_game_mission_old_decision_details):
        mission_id = decision_details_data['mission_id']
        day_id = decision_details_data['day_id']
        details = decision_details_data['details']
        if p2p_game_mission_old_decision_details is None:
            p2p_game_mission_decision_details = P2pGameMissionDecisionDetails(mission_id, day_id, details)
            return p2p_game_mission_decision_details
        else:
            p2p_game_mission_old_decision_details.details = details
            return p2p_game_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_p2p_game_mission(game_session_id, participant_id):
        p2p_game_mission = P2pGameMission('Ma mission', 'Participant', game_session_id, participant_id)
        return p2p_game_mission


    @staticmethod
    def create_scores_dtos(p2p_game_missions, scores):
        scores_dtos = {}
        if p2p_game_missions is None:
            p2p_game_missions = []
        for mission in p2p_game_missions:
            p2p_game_mission_dto = P2pGameGameServiceHelper.create_mission_dto(mission)
            p2p_game_score_dto = P2pGameScoreDTO()
            p2p_game_score_dto.p2p_game_mission = p2p_game_mission_dto
            scores_dtos[mission.id] = p2p_game_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
            p2p_game_score_dto = scores_dtos[mission_id]
            p2p_game_score_dto.score1 = int(row[1])
            p2p_game_score_dto.score2 = int(row[2])
        return list(scores_dtos.values())

    @staticmethod
    def create_mission_day(mission_id, day_id):
        p2p_game_mission_day = P2pGameMissionDay(0, 0,  0, -1, mission_id, day_id)
        return p2p_game_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_p2p_game_mission_badges(participant_mission, p2p_game_badges):
        p2p_game_mission_badges = []
        for p2p_game_badge in p2p_game_badges:
            p2p_game_mission_badge = P2pGameMissionBadge(participant_mission.id, p2p_game_badge.id, 0)
            p2p_game_mission_badges.append(p2p_game_mission_badge)
        return p2p_game_mission_badges

    @staticmethod
    def create_p2p_game_mission_days(participant_mission, p2p_game_days):
        p2p_game_mission_days = []
        first_day = None
        for p2p_game_day in p2p_game_days:
            p2p_game_mission_day = P2pGameMissionDay(0, 0, 0, -1, participant_mission.id, p2p_game_day.id)
            if p2p_game_day.id == 1:
                first_day = p2p_game_mission_day
            p2p_game_mission_days.append(p2p_game_mission_day)
        first_day.status = 0
        first_day.set_start_date()
        return p2p_game_mission_days

    @staticmethod
    def create_days_dtos(mission_days, mission_decisions):
        day_dtos = {}
        for mission_day in mission_days:
            day_dto = P2pGameDayDTO()
            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(p2p_game_mission_decision_details):
        decision_details_dtos = []
        for decision_details in p2p_game_mission_decision_details:
            decision_details_dto = P2pGameDecisionDetailsDTO()
            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(p2p_game_mission_day, mission_badges_dtos, success):
        return {'mission_id': p2p_game_mission_day.mission_id, 'day_id': p2p_game_mission_day.day_id, 'stars': p2p_game_mission_day.stars,
                'score1': p2p_game_mission_day.score1, 'score2': p2p_game_mission_day.score2,
                'badges': mission_badges_dtos, 'success': success}

    @staticmethod
    def create_not_closing_day_dto(p2p_game_mission_day):
        return {'mission_id': p2p_game_mission_day.mission_id, 'day_id': p2p_game_mission_day.day_id, 'stars': p2p_game_mission_day.stars,
                'score1': p2p_game_mission_day.score1, 'score2': p2p_game_mission_day.score2,
                'badges': [], 'success': False}


    @staticmethod
    def create_day1_story_steps(p2p_game_mission_day, p2p_game_decision_repository):
        mission_id = p2p_game_mission_day.mission_id
        activity1 = int(p2p_game_decision_repository.get_aggregated_decision_scores([i for i in range(1, 4)], mission_id)[0][0])
        activity2 = int(p2p_game_decision_repository.get_aggregated_decision_scores([i for i in range(4, 7)], mission_id)[0][0])
        activity3 = int(p2p_game_decision_repository.get_aggregated_decision_scores([i for i in range(7, 31)], mission_id)[0][0])
        activity4_1 = int(p2p_game_decision_repository.get_aggregated_decision_scores([i for i in range(31, 35)], mission_id)[0][0])
        activity4_2 = int(p2p_game_decision_repository.get_aggregated_decision_scores([i for i in range(35, 39)], mission_id)[0][0])
        activity4_3 = int(p2p_game_decision_repository.get_aggregated_decision_scores([i for i in range(39, 43)], mission_id)[0][0])
        activity4_4 = int(p2p_game_decision_repository.get_aggregated_decision_scores([i for i in range(43, 47)], mission_id)[0][0])
        story_steps = [P2pGameMissionStorySteps(1, mission_id, activity1, 0, ""),
                       P2pGameMissionStorySteps(2, mission_id, activity2, 0, ""),
                       P2pGameMissionStorySteps(3, mission_id, activity3, 0, ""),
                       P2pGameMissionStorySteps(4, mission_id, activity4_1, 0, ""),
                       P2pGameMissionStorySteps(5, mission_id, activity4_2, 0, ""),
                       P2pGameMissionStorySteps(6, mission_id, activity4_3, 0, ""),
                       P2pGameMissionStorySteps(7, mission_id, activity4_4, 0, ""),
                       P2pGameMissionStorySteps(8, mission_id, activity1 + activity2 + activity3 + activity4_1 + activity4_2 + activity4_3 + activity4_4, 0, "")]
        return story_steps


    @staticmethod
    def create_day2_story_steps(p2p_game_mission_day, p2p_game_decision_repository):
        mission_id = p2p_game_mission_day.mission_id
        activité1 = int(p2p_game_decision_repository.get_aggregated_decision_scores([i for i in range(47, 77)], mission_id)[0][0])
        activité2 = p2p_game_decision_repository.get_aggregated_decision_scores([i for i in range(77, 127)], mission_id)
        activité3 = int(p2p_game_decision_repository.get_aggregated_decision_scores([i for i in range(127, 132)],
                                                                                           mission_id)[0][1])
        activité4 = int(p2p_game_decision_repository.get_aggregated_decision_scores([i for i in range(132, 142)], mission_id)[0][1])
        story_steps = [P2pGameMissionStorySteps(6, mission_id, activité1, 0, ""),
                       P2pGameMissionStorySteps(7, mission_id, int(activité2[0][0]), int(activité2[0][1]), ""),
                       P2pGameMissionStorySteps(8, mission_id, 0, activité3, ""),
                       P2pGameMissionStorySteps(9, mission_id, 0, activité4, ""),
                       P2pGameMissionStorySteps(10, mission_id, activité1 +  int(activité2[0][0]) + int(activité2[0][1])+ activité3+ activité4, "")]
        return story_steps

    @staticmethod
    def create_day3_story_steps(p2p_game_mission_day, p2p_game_decision_repository):
        mission_id = p2p_game_mission_day.mission_id
        activité1 = int(p2p_game_decision_repository.get_aggregated_decision_scores([i for i in range(142, 150)], mission_id)[0][0])
        story_steps = [
                       P2pGameMissionStorySteps(11, mission_id, activité1, 0, ""),
                     ]
        return story_steps
    @staticmethod
    def create_mission_story_steps_dtos(p2p_game_mission_story_steps):
        p2p_game_mission_story_steps_dtos = []
        for story_step in p2p_game_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
            }
            p2p_game_mission_story_steps_dtos.append(story_step_dto)
        return p2p_game_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/p2p_game/"+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_p2p_game.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), 350, attendee_name.upper())

        # certificate number
        c.setFont('Source Serif Pro Bold', 13, leading=None)
        c.setFillColor(HexColor('#545454'))
        c.drawString(613, 144, certificat_number)
        # expiry date
        c.setFont('Source Serif Pro Bold', 13, leading=None)
        c.setFillColor(HexColor('#545454'))
        c.drawString(613, 127, expiry_date.upper())
        c.showPage()
        c.save()
        return pdf_file_path, file_name



