using System;
using Microsoft.Extensions.Logging;
using ms_namingservice.Objects;
using ms_namingservice.Objects.SavedData;

namespace ms_namingservice.Mapping.ValuesMapping;

/// <summary>
/// Class handling with method for reference mapping.
/// </summary>
public class ReferenceMapping
{
    /// <summary>
    /// Represents the logger instance for this class.
    /// </summary>
    private static ILogger Logger = Logging.LoggerFactory.CreateLogger<ReferenceMapping>();
    
    /// <summary>
    /// Getting the URL of the reference to the website.
    /// </summary>
    /// <param name="framework">Framework to map the reference.</param>
    /// <returns>Returns the URL to the MITRE ATT&CK site in case of MITRE framework or null in case of ENISA framework.</returns>
    public async static Task<string> GetReference(string framework)
    {
        string reference = string.Empty;

        if (framework.Equals(Const.Mitre))
        {
            //Checking, if the URL can be formatted based on its tags
            if (InputData.Input.Tags[0].Equals("null"))
            {
                return null;
            }

            //Constants regarding the MITRE ATT&CK website
            const string tacticURL = "https://attack.mitre.org/tactics/";
            const string techniqueURL = "https://attack.mitre.org/techniques/";
            
            string technique = string.Empty;
            string tactic = string.Empty;

            //Formatting MITRE ATT&CK URL, if the subcategory (technique) is recognised from the tags
            if (!(InputData.Input.Tags[1].Equals("null") || InputData.Input.Tags[1] == null) && InputData.Input.Tags[1].StartsWith("attack.t"))
            {
                technique = InputData.Input.Tags[1].Substring("attack.".Length).ToUpper(); //Removing the attack. and capitalizing the tags, for example from attack.t123 to T123
                reference = techniqueURL + technique;
            }
            else //For the categories (tactics) that are recognised from the tags
            {
                try
                {
                    //Checking, if the tactic can be recognised
                    if ((InputData.Input.Tags.Length >= 2 &&
                         !(InputData.Input.Tags[0].Contains("attack.t") ||
                           InputData.Input.Tags[1].Contains("attack.t"))) ||
                        (InputData.Input.Tags.Length == 1 && !InputData.Input.Tags[0].Contains("attack.t")))
                    {
                        string tag = InputData.Input.Tags[0];

                        //Mapping MITRE ATT&CK tactics in tag format to its tactic ID from the MITRE ATT&CK website
                        Dictionary<string, string> cases = new Dictionary<string, string>
                        {
                            {"attack.reconnaisance", "TA0043"},
                            {"attack.resource_development", "TA0042"},
                            {"attack.initial_access", "TA0001"},
                            {"attack.execution", "TA0002"},
                            {"attack.persistence", "TA0003"},
                            {"attack.privilege_escalation", "TA0004"},
                            {"attack.defense_evasion", "TA0005"},
                            {"attack.credential_access", "TA0006"},
                            {"attack.discovery", "TA0007"},
                            {"attack.lateral_movement", "TA0008"},
                            {"attack.collection", "TA0009"},
                            {"attack.command_and_control", "TA0011"},
                            {"attack.exfiltration", "TA0010"},
                            {"attack.impact", "TA0040"}
                        };

                        //Getting MITRE ATT&CK tactic URL
                        if (cases.ContainsKey(tag))
                        {
                            tactic = tacticURL + cases[tag];
                        }

                        reference = tactic;
                    }
                }
                catch (Exception e)
                {
                    Logger.LogError(e.Message); //Log error
                }   
            }
        }
        else if (framework.Equals(Const.Enisa))
        {
            reference = null; //ENISA does not have any reference
        }

        Logger.LogInformation("Reference created: " + reference); //Log
        return reference;
    }
}