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.insights.insights_mission import InsightsMission
from app.main.data_model.games.insights.insights_mission_badge import InsightsMissionBadge
from app.main.data_model.games.insights.insights_mission_day import InsightsMissionDay
from app.main.data_model.games.insights.insights_mission_decision import InsightsMissionDecision
from app.main.data_model.games.insights.insights_mission_decision_details import InsightsMissionDecisionDetails
from app.main.data_model.games.insights.insights_mission_story_steps import InsightsMissionStorySteps
from app.main.util.json_objects.games.insights.insights_day_dto import InsightsDayDTO
from app.main.util.json_objects.games.insights.insights_decision_details_dto import InsightsDecisionDetailsDTO
from app.main.util.json_objects.games.insights.insights_mission_dto import InsightsMissionDTO
from app.main.util.json_objects.games.insights.insights_score_dto import InsightsScoreDTO


class InsightsGameServiceHelper:

    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 = InsightsMissionDTO()
        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']
        insights_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
            insights_mission_decision = InsightsMissionDecision(mission_id, decision_id, day_id)
            insights_mission_decisions.append(insights_mission_decision)
        return insights_mission_decisions, decision_ids_to_delete

    @staticmethod
    def create_mission_decision_details(decision_details_data, insights_mission_old_decision_details):
        mission_id = decision_details_data['mission_id']
        day_id = decision_details_data['day_id']
        details = decision_details_data['details']
        if insights_mission_old_decision_details is None:
            insights_mission_decision_details = InsightsMissionDecisionDetails(mission_id, day_id, details)
            return insights_mission_decision_details
        else:
            insights_mission_old_decision_details.details = details
            return insights_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_insights_mission(game_session_id, participant_id):
        insights_mission = InsightsMission('Ma mission', 'Participant', game_session_id, participant_id)
        return insights_mission

    @staticmethod
    def create_scores_dtos(insights_missions, scores):
        scores_dtos = {}
        if insights_missions is None:
            insights_missions = []

        for mission in insights_missions:
            insights_mission_dto = InsightsGameServiceHelper.create_mission_dto(mission)
            insights_score_dto = InsightsScoreDTO()
            insights_score_dto.insights_mission = insights_mission_dto
            scores_dtos[mission.id] = insights_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
            insights_score_dto = scores_dtos[mission_id]
            insights_score_dto.score1 = int(row[1])
            insights_score_dto.score2 = int(row[2])
        return list(scores_dtos.values())

    @staticmethod
    def create_mission_day(mission_id, day_id):
        insights_mission_day = InsightsMissionDay(0, 0,  0, -1, mission_id, day_id)
        return insights_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_insights_mission_badges(participant_mission, insights_badges):
        insights_mission_badges = []
        for insights_badge in insights_badges:
            insights_mission_badge = InsightsMissionBadge(participant_mission.id, insights_badge.id, 0)
            insights_mission_badges.append(insights_mission_badge)
        return insights_mission_badges

    @staticmethod
    def create_insights_mission_days(participant_mission, insights_days):
        insights_mission_days = []
        first_day = None
        for insights_day in insights_days:
            insights_mission_day = InsightsMissionDay(0, 0, 0, -1, participant_mission.id, insights_day.id)
            if insights_day.id == 1:
                first_day = insights_mission_day
            insights_mission_days.append(insights_mission_day)
        first_day.status = 0
        first_day.set_start_date()
        return insights_mission_days

    @staticmethod
    def create_days_dtos(mission_days, mission_decisions):
        day_dtos = {}
        for mission_day in mission_days:
            day_dto = InsightsDayDTO()
            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(insights_mission_decision_details):
        decision_details_dtos = []
        for decision_details in insights_mission_decision_details:
            decision_details_dto = InsightsDecisionDetailsDTO()
            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(insights_mission_day, mission_badges_dtos, success):
        return {'mission_id': insights_mission_day.mission_id, 'day_id': insights_mission_day.day_id, 'stars': insights_mission_day.stars,
                'score1': insights_mission_day.score1, 'score2': insights_mission_day.score2,
                'badges': mission_badges_dtos, 'success': success}

    @staticmethod
    def create_not_closing_day_dto(insights_mission_day):
        return {'mission_id': insights_mission_day.mission_id, 'day_id': insights_mission_day.day_id, 'stars': insights_mission_day.stars,
                'score1': insights_mission_day.score1, 'score2': insights_mission_day.score2,
                'badges': [], 'success': False}

    @staticmethod
    def create_day1_story_steps(insights_mission_day, insights_decision_repository):
        mission_id = insights_mission_day.mission_id
        quiz = int(insights_decision_repository.get_aggregated_decision_scores([i for i in range(1, 5)], mission_id)[0][0])
        drag_and_drop = int(insights_decision_repository.get_aggregated_decision_scores([i for i in range(5, 20)], mission_id)[0][0])

        story_steps = [InsightsMissionStorySteps(1, mission_id, quiz, 0, ""),
                       InsightsMissionStorySteps(2, mission_id, drag_and_drop, 0, ""),
                       InsightsMissionStorySteps(3, mission_id, quiz + drag_and_drop, 0, "")]
        return story_steps

    @staticmethod
    def create_day2_story_steps(insights_mission_day, insights_decision_repository):
        mission_id = insights_mission_day.mission_id
        classement = int(insights_decision_repository.get_aggregated_decision_scores([i for i in range(20, 27)], mission_id)[0][1])
        drag_and_drop = insights_decision_repository.get_aggregated_decision_scores([i for i in range(27, 53)], mission_id)
        quiz1 = int(insights_decision_repository.get_aggregated_decision_scores([i for i in range(53, 57)], mission_id)[0][0])
        quiz2 = int(insights_decision_repository.get_aggregated_decision_scores([i for i in range(57, 60)], mission_id)[0][0])

        story_steps = [InsightsMissionStorySteps(4, mission_id, classement, 0, ""),
                       InsightsMissionStorySteps(5, mission_id, int(drag_and_drop[0][0]), int(drag_and_drop[0][1]), ""),
                       InsightsMissionStorySteps(6, mission_id, quiz1, 0, ""),
                       InsightsMissionStorySteps(7, mission_id, quiz2, 0, ""),
                       InsightsMissionStorySteps(8, mission_id, int(drag_and_drop[0][0]) + quiz1 + quiz2,
                                            classement + int(drag_and_drop[0][1]), "")]
        return story_steps

    @staticmethod
    def create_day3_story_steps(insights_mission_day, insights_decision_repository):
        mission_id = insights_mission_day.mission_id
        multiselection = int(insights_decision_repository.get_aggregated_decision_scores([i for i in range(60, 75)], mission_id)[0][0])
        drag_and_drop = int(insights_decision_repository.get_aggregated_decision_scores([i for i in range(75, 90)], mission_id)[0][0])

        total = multiselection + drag_and_drop
        story_steps = [
                       InsightsMissionStorySteps(9, mission_id, multiselection, 0, ""),
                       InsightsMissionStorySteps(10, mission_id, drag_and_drop, 0, ""),
                       InsightsMissionStorySteps(11, mission_id, total, 0, ""),
                     ]
        return story_steps

    @staticmethod
    def create_day4_story_steps(insights_mission_day, insights_decision_repository):
        mission_id = insights_mission_day.mission_id
        drag_and_drop = int(insights_decision_repository.get_aggregated_decision_scores([i for i in range(90, 107)], mission_id)[0][0])
        quiz1 = int(insights_decision_repository.get_aggregated_decision_scores([i for i in range(107, 110)], mission_id)[0][0])
        quiz2 = int(insights_decision_repository.get_aggregated_decision_scores([i for i in range(110, 113)], mission_id)[0][0])
        quiz3 = int(insights_decision_repository.get_aggregated_decision_scores([i for i in range(113, 116)], mission_id)[0][0])

        story_steps = [InsightsMissionStorySteps(12, mission_id, drag_and_drop, 0, ""),
                       InsightsMissionStorySteps(13, mission_id, quiz1, 0, ""),
                       InsightsMissionStorySteps(14, mission_id, quiz2, 0, ""),
                       InsightsMissionStorySteps(15, mission_id, quiz3, 0, ""),
                       InsightsMissionStorySteps(16, mission_id, drag_and_drop + quiz1 + quiz2+
                                            quiz3,0, "")]
        return story_steps

    @staticmethod
    def create_day5_story_steps(insights_mission_day, insights_decision_repository):
        mission_id = insights_mission_day.mission_id
        drag_and_drop = int(insights_decision_repository.get_aggregated_decision_scores([i for i in range(116, 124)], mission_id)[0][0])
        quiz = int(insights_decision_repository.get_aggregated_decision_scores([i for i in range(124, 127)], mission_id)[0][0])
        dossier_collecte = int(insights_decision_repository.get_aggregated_decision_scores([i for i in range(127, 135)], mission_id)[0][1])
        dossier_descriptive = int(insights_decision_repository.get_aggregated_decision_scores([i for i in range(135, 143)], mission_id)[0][1])
        dossier_predictive = int(insights_decision_repository.get_aggregated_decision_scores([i for i in range(143, 151)], mission_id)[0][1])
        dossier_prescriptive = int(insights_decision_repository.get_aggregated_decision_scores([i for i in range(151, 158)], mission_id)[0][1])
        story_steps = [InsightsMissionStorySteps(17, mission_id, drag_and_drop, 0, ""),
                       InsightsMissionStorySteps(18, mission_id, quiz, 0, ""),
                       InsightsMissionStorySteps(19, mission_id, dossier_collecte, 0, ""),
                       InsightsMissionStorySteps(20, mission_id, dossier_descriptive, 0, ""),
                       InsightsMissionStorySteps(21, mission_id, dossier_predictive, 0, ""),
                       InsightsMissionStorySteps(22, mission_id, dossier_prescriptive, 0, ""),
                       InsightsMissionStorySteps(23, mission_id, drag_and_drop+quiz, dossier_collecte + dossier_descriptive + dossier_predictive + dossier_prescriptive, "")]
        return story_steps


    @staticmethod
    def create_mission_story_steps_dtos(insights_mission_story_steps):
        insights_mission_story_steps_dtos = []
        for story_step in insights_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
            }
            insights_mission_story_steps_dtos.append(story_step_dto)
        return insights_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/insights/"+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_insights.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



