# Copyright (c) AIRBUS and its affiliates.
# This source code is licensed under the MIT license found in the
# LICENSE file in the root directory of this source tree.

from __future__ import annotations

from typing import Dict, Tuple

from skdecide.discrete_optimization.rcpsp_multiskill.rcpsp_multiskill import (
    Employee,
    MS_RCPSPModel,
    SkillDetail,
)


def parse_imopse(input_data, max_horizon=None):
    # parse the input
    # print('input_data\n',input_data)
    lines = input_data.split("\n")

    # "General characteristics:
    #     Tasks: 161
    #     Resources: 10
    #     Precedence relations: 321
    #     Number of skill types: 9
    #     ====================================================================================================================
    #     ResourceID 	 Salary 	 Skills
    #     1	 	 	14.2	 	 Q2: 0 	  Q3: 2 	  Q1: 0 	  Q4: 2 	  Q7: 1 	  Q8: 2
    #     2	 	 	31.2	 	 Q0: 0 	  Q4: 2 	  Q7: 1 	  Q3: 1 	  Q8: 2 	  Q2: 0
    #     3	 	 	34.4	 	 Q4: 0 	  Q2: 1 	  Q6: 2 	  Q3: 1 	  Q0: 1 	  Q5: 0
    #     4	 	 	26.0	 	 Q5: 2 	  Q1: 1 	  Q4: 1 	  Q8: 2 	  Q0: 2 	  Q2: 2
    #     5	 	 	30.8	 	 Q8: 0 	  Q7: 1 	  Q3: 1 	  Q1: 2 	  Q4: 1 	  Q5: 1
    #     6	 	 	17.3	 	 Q6: 1 	  Q3: 2 	  Q4: 2 	  Q2: 0 	  Q7: 2 	  Q1: 0
    #     7	 	 	19.8	 	 Q1: 2 	  Q4: 2 	  Q5: 0 	  Q7: 1 	  Q3: 1 	  Q6: 2
    #     8	 	 	35.8	 	 Q2: 1 	  Q0: 1 	  Q3: 2 	  Q6: 0 	  Q7: 0 	  Q8: 1
    #     9	 	 	37.6	 	 Q7: 0 	  Q5: 2 	  Q2: 0 	  Q1: 0 	  Q0: 1 	  Q3: 1
    #     10	 	23.5	     Q8: 1    Q5: 1       Q1: 2       Q6: 0       Q4: 0 	  Q3: 2 	 "
    nb_task = None
    nb_worker = None
    nb_precedence_relation = None
    nb_skills = None
    resource_zone = False
    task_zone = False
    resource_dict = {}
    task_dict = {}
    real_skills_found = set()
    for line in lines:
        words = line.split()
        if len(words) == 2 and words[0] == "Tasks:":
            nb_task = int(words[1])
            continue
        if len(words) == 2 and words[0] == "Resources:":
            nb_worker = int(words[1])
            continue
        if len(words) == 3 and words[0] == "Precedence" and words[1] == "relations:":
            nb_precedence_relation = int(words[2])
            continue
        if len(words) == 5 and words[0] == "Number" and words[1] == "of":
            nb_skills = int(words[4])
            continue
        if len(words) == 0:
            continue
        if words[0] == "ResourceID":
            resource_zone = True
            continue
        if words[0] == "TaskID":
            task_zone = True
            continue
        if resource_zone:
            if words[0][0] == "=":
                resource_zone = False
                continue
            else:
                id_worker = words[0]
                resource_dict[id_worker] = {"salary": float(words[1])}
                for word in words[2:]:
                    if word[0] == "Q":
                        current_skill = word[:-1]
                        continue
                    resource_dict[id_worker][current_skill] = int(word) + 1
                    real_skills_found.add(current_skill)
        if task_zone:
            if words[0][0] == "=":
                task_zone = False
                continue
            else:
                task_id = int(words[0])
                if task_id not in task_dict:
                    task_dict[task_id] = {"id": task_id, "successors": [], "skills": {}}
                task_dict[task_id]["duration"] = int(words[1])
            i = 2
            while i < len(words):
                if words[i][0] == "Q":
                    current_skill = words[i][:-1]
                    task_dict[task_id]["skills"][current_skill] = int(words[i + 1]) + 1
                    real_skills_found.add(current_skill)
                    i = i + 2
                    continue
                else:
                    if "precedence" not in task_dict[task_id]:
                        task_dict[task_id]["precedence"] = []
                    task_dict[task_id]["precedence"] += [int(words[i])]
                    if int(words[i]) not in task_dict:
                        task_dict[int(words[i])] = {
                            "id": int(words[i]),
                            "successors": [],
                            "skills": {},
                        }
                    if "successors" not in task_dict[int(words[i])]:
                        task_dict[int(words[i])]["successors"] = []
                    task_dict[int(words[i])]["successors"] += [task_id]
                    i += 1
    # print(resource_dict)
    # print(task_dict)
    sorted_task_names = sorted(task_dict.keys())
    task_id_to_new_name = {
        sorted_task_names[i]: i + 2 for i in range(len(sorted_task_names))
    }
    new_tame_to_original_task_id = {
        task_id_to_new_name[ind]: ind for ind in task_id_to_new_name
    }
    mode_details = {
        task_id_to_new_name[task_id]: {1: {"duration": task_dict[task_id]["duration"]}}
        for task_id in task_dict
    }
    resource_dict = {int(i): resource_dict[i] for i in resource_dict}
    # skills = set(["Q"+str(i) for i in range(nb_skills)])
    skills = real_skills_found
    for task_id in task_dict:
        for skill in skills:
            req_squill = task_dict[task_id]["skills"].get(skill, 0.0)
            mode_details[task_id_to_new_name[task_id]][1][skill] = req_squill
    mode_details[1] = {1: {"duration": 0}}
    for skill in skills:
        mode_details[1][1][skill] = int(0)
    max_t = max(mode_details)
    mode_details[max_t + 1] = {1: {"duration": 0}}
    for skill in skills:
        mode_details[max_t + 1][1][skill] = int(0)
    successors = {
        task_id_to_new_name[task_id]: [
            task_id_to_new_name[t] for t in task_dict[task_id]["successors"]
        ]
        + [max_t + 1]
        for task_id in task_dict
    }
    successors[max_t + 1] = []
    successors[1] = [k for k in successors]
    # max_horizon = 2*sum([task_dict[task_id]["duration"] for task_id in task_dict])
    max_horizon = 300 if max_horizon is None else max_horizon
    return (
        MS_RCPSPModel(
            skills_set=set(real_skills_found),
            resources_set=set(),
            non_renewable_resources=set(),
            resources_availability={},
            employees={
                res: Employee(
                    dict_skill={
                        skill: SkillDetail(
                            skill_value=resource_dict[res][skill],
                            efficiency_ratio=1.0,
                            experience=1.0,
                        )
                        for skill in resource_dict[res]
                        if skill != "salary"
                    },
                    salary=resource_dict[res]["salary"],
                    calendar_employee=[True] * max_horizon,
                )
                for res in resource_dict
            },
            employees_availability=[len(resource_dict)] * max_horizon,
            mode_details=mode_details,
            successors=successors,
            horizon=max_horizon,
            source_task=1,
            sink_task=max_t + 1,
            one_unit_per_task_max=True,
        ),
        new_tame_to_original_task_id,
    )


def parse_file(file_path, max_horizon=None) -> Tuple[MS_RCPSPModel, Dict]:
    with open(file_path, "r") as input_data_file:
        input_data = input_data_file.read()
        rcpsp_model, new_tame_to_original_task_id = parse_imopse(
            input_data, max_horizon
        )
        return rcpsp_model, new_tame_to_original_task_id
