using Adaptation.FileHandlers.ConvertExcelToJson;
using Adaptation.FileHandlers.json.WorkItems;
using Adaptation.Shared;
using Adaptation.Shared.Duplicator;
using Adaptation.Shared.Methods;
using Microsoft.TeamFoundation.WorkItemTracking.WebApi;
using Microsoft.TeamFoundation.WorkItemTracking.WebApi.Models;
using Microsoft.VisualStudio.Services.WebApi.Patch;
using Microsoft.VisualStudio.Services.WebApi.Patch.Json;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;

namespace Adaptation.FileHandlers.json;

public class ProcessData : IProcessData
{

    private readonly List<object> _Details;

    List<object> Shared.Properties.IProcessData.Details => _Details;

    public ProcessData(IFileRead fileRead, Logistics logistics, List<FileInfo> fileInfoCollection, HttpClient httpClient, string basePage, string api, string query, WorkItemTrackingHttpClient workItemTrackingHttpClient, string project, ReadOnlyDictionary<string, string> assignedToNameToUser, ReadOnlyDictionary<string, string> requestorNameToUser, string json)
    {
        fileInfoCollection.Clear();
        _Details = new List<object>();
        Parse(fileRead, logistics, fileInfoCollection, httpClient, basePage, api, query, workItemTrackingHttpClient, project, assignedToNameToUser, requestorNameToUser, json);
    }

    string IProcessData.GetCurrentReactor(IFileRead fileRead, Logistics logistics, Dictionary<string, string> reactors)
        => throw new Exception(string.Concat("See ", nameof(Parse)));

    Tuple<string, Test[], JsonElement[], List<FileInfo>> IProcessData.GetResults(IFileRead fileRead, Logistics logistics, List<FileInfo> fileInfoCollection)
        => new(logistics.Logistics1[0], Array.Empty<Test>(), Array.Empty<JsonElement>(), fileInfoCollection);

    internal static List<Description> GetDescriptions(JsonElement[] jsonElements) => throw new NotImplementedException();

#nullable enable

    private static void AddPatch(JsonPatchDocument document, string path, object value) => document.Add(new JsonPatchOperation { From = null, Operation = Operation.Add, Path = path, Value = value });

    private static Dictionary<string, FIBacklogMesa> GetFIBacklogMesaCollection(string json)
    {
        Dictionary<string, FIBacklogMesa> results = new();
        string key;
        FIBacklogMesa[]? fiBacklogMesaCollection;
        fiBacklogMesaCollection = JsonSerializer.Deserialize<FIBacklogMesa[]>(json, new JsonSerializerOptions() { PropertyNameCaseInsensitive = true });
        if (fiBacklogMesaCollection is null || !fiBacklogMesaCollection.Any())
            throw new NullReferenceException();
        foreach (FIBacklogMesa fiBacklogMesa in fiBacklogMesaCollection)
        {
            if (string.IsNullOrEmpty(fiBacklogMesa.Req))
                continue;
            if (string.IsNullOrEmpty(fiBacklogMesa.Submitted))
                continue;
            if (string.IsNullOrEmpty(fiBacklogMesa.Requestor))
                continue;
            key = $"{fiBacklogMesa.Req} - ";
            if (results.ContainsKey(key))
                continue;
            results.Add(key, fiBacklogMesa);
        }
        return results;
    }

    private static string GetIds(HttpClient httpClient, string basePage, string api, string query)
    {
        StringBuilder result = new();
        Task<HttpResponseMessage> httpResponseMessageTask = httpClient.GetAsync(string.Concat(basePage, api, query));
        httpResponseMessageTask.Wait();
        if (!httpResponseMessageTask.Result.IsSuccessStatusCode)
            throw new Exception(httpResponseMessageTask.Result.StatusCode.ToString());
        Task<Stream> streamTask = httpResponseMessageTask.Result.Content.ReadAsStreamAsync();
        streamTask.Wait();
        if (!streamTask.Result.CanRead)
            throw new NullReferenceException(nameof(streamTask));
        WIQL.Root? root = JsonSerializer.Deserialize<WIQL.Root>(streamTask.Result, new JsonSerializerOptions() { PropertyNameCaseInsensitive = true });
        streamTask.Result.Dispose();
        if (root is null || root.WorkItems is null)
            throw new NullReferenceException(nameof(root));
        foreach (WIQL.WorkItem workItem in root.WorkItems)
            _ = result.Append(workItem.Id).Append(',');
        if (result.Length > 0)
            _ = result.Remove(result.Length - 1, 1);
        return result.ToString();
    }

    private static Value[] GetWorkItems(HttpClient httpClient, string basePage, string api, string ids)
    {
        Value[]? results;
        Task<HttpResponseMessage> httpResponseMessageTask = httpClient.GetAsync(string.Concat(basePage, api, $"/workitems?ids={ids}"));
        httpResponseMessageTask.Wait();
        if (!httpResponseMessageTask.Result.IsSuccessStatusCode)
            throw new Exception(httpResponseMessageTask.Result.StatusCode.ToString());
        Task<Stream> streamTask = httpResponseMessageTask.Result.Content.ReadAsStreamAsync();
        streamTask.Wait();
        if (!streamTask.Result.CanRead)
            throw new NullReferenceException(nameof(streamTask));
        JsonElement? jsonElement = JsonSerializer.Deserialize<JsonElement>(streamTask.Result);
        if (jsonElement is null || jsonElement.Value.ValueKind != JsonValueKind.Object)
            throw new NullReferenceException(nameof(jsonElement));
        results = JsonSerializer.Deserialize<Value[]>(jsonElement.Value.EnumerateObject().Last().Value);
        if (results is null || !results.Any())
            throw new NullReferenceException(nameof(results));
        return results;
    }

    private static ReadOnlyCollection<ValueWithReq> GetValueWithReqCollection(IReadOnlyList<Value> workItems)
    {
        List<ValueWithReq> results = new();
        string[] segments;
        foreach (Value value in workItems)
        {
            segments = value.Fields.SystemTitle.Split('-');
            if (segments.Length < 2)
                continue;
            if (!int.TryParse(segments[0], out int req) || req == 0)
                continue;
            results.Add(new(value, req));
        }
        return new(results);
    }

    private static ReadOnlyCollection<ValueWithReq> RemoveFrom(Dictionary<string, FIBacklogMesa> keyToFIBacklogMesa, ReadOnlyCollection<ValueWithReq> valueWithReqCollection)
    {
        List<ValueWithReq> results = new();
        foreach (ValueWithReq valueWithReq in valueWithReqCollection)
        {
            if (keyToFIBacklogMesa.Remove($"{valueWithReq.Req} - "))
                continue;
            results.Add(valueWithReq);
        }
        return new(results);
    }

    private static void Update(WorkItemTrackingHttpClient workItemTrackingHttpClient, string sync, ValueWithReq valueWithReq)
    {
        JsonPatchDocument result = new();
        AddPatch(result, "/fields/System.Tags", sync);
        Task<WorkItem> workItem = workItemTrackingHttpClient.UpdateWorkItemAsync(result, valueWithReq.Value.Id);
        workItem.Wait();
    }

    private static DateTime? GetCommitDate(FIBacklogMesa fiBacklogMesa)
    {
        DateTime? result;
        if (!DateTime.TryParseExact(fiBacklogMesa.CommitDate.Split(' ').First(), "MM/dd/yyyy", CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime dateTime) && dateTime != DateTime.MinValue)
            result = null;
        else
            result = dateTime.AddHours(12).ToUniversalTime();
        return result;
    }

    private static string? GetMappedState(FIBacklogMesa fiBacklogMesa) =>
        fiBacklogMesa.Status == "CMP" ? "Closed" : fiBacklogMesa.Status == "UAT" ? "Resolved" : fiBacklogMesa.Status == "In process" ? "Active" : null;

    private static void SetSyncTag(WorkItemTrackingHttpClient workItemTrackingHttpClient, ReadOnlyDictionary<string, string> requestorNameToUser, Dictionary<string, FIBacklogMesa> keyToFIBacklogMesa, ReadOnlyCollection<ValueWithReq> valueWithReqCollection)
    {
        string key;
        bool isBugFix;
        string? state;
        List<string> tags;
        TimeSpan timeSpan;
        DateTime? dateTime;
        List<string> compareTags;
        const string sync = "Sync";
        FIBacklogMesa? fiBacklogMesa;
        foreach (ValueWithReq valueWithReq in valueWithReqCollection)
        {
            key = $"{valueWithReq.Req} - ";
            compareTags = GetTags(valueWithReq.Value.Fields);
            if (compareTags.Contains(sync))
                continue;
            if (!keyToFIBacklogMesa.TryGetValue(key, out fiBacklogMesa))
                continue;
            tags = GetTags(fiBacklogMesa);
            isBugFix = fiBacklogMesa.Priority == "0 - BugFix";
            _ = requestorNameToUser.TryGetValue(fiBacklogMesa.Requestor, out string? requestorUser);
            if (!string.IsNullOrEmpty(requestorUser) && (valueWithReq.Value.Fields.SystemAssignedTo is null || !valueWithReq.Value.Fields.SystemAssignedTo.UniqueName.Equals(requestorUser, StringComparison.CurrentCultureIgnoreCase)))
            {
                Update(workItemTrackingHttpClient, sync, valueWithReq);
                continue;
            }
            if (valueWithReq.Value.Fields.SystemTitle != $"{valueWithReq.Req} - {fiBacklogMesa.Subject}")
            {
                Update(workItemTrackingHttpClient, sync, valueWithReq);
                continue;
            }
            foreach (string tag in tags)
            {
                if (compareTags.Contains(tag))
                    continue;
                _ = tags.Remove(tag);
                break;
            }
            if (tags.Count != compareTags.Count)
            {
                Update(workItemTrackingHttpClient, sync, valueWithReq);
                continue;
            }
            if ((isBugFix && valueWithReq.Value.Fields.SystemWorkItemType != "Bug") || (!isBugFix && valueWithReq.Value.Fields.SystemWorkItemType == "Bug"))
            {
                Update(workItemTrackingHttpClient, sync, valueWithReq);
                continue;
            }
            if (!isBugFix)
            {
                if (!int.TryParse(fiBacklogMesa.Priority.Substring(0, 1), out int priority))
                {
                    Update(workItemTrackingHttpClient, sync, valueWithReq);
                    continue;
                }
                if (valueWithReq.Value.Fields.MicrosoftVSTSCommonPriority != priority)
                {
                    Update(workItemTrackingHttpClient, sync, valueWithReq);
                    continue;
                }
            }
            state = GetMappedState(fiBacklogMesa);
            if (!string.IsNullOrEmpty(state) && valueWithReq.Value.Fields.SystemState != state)
            {
                Update(workItemTrackingHttpClient, sync, valueWithReq);
                continue;
            }
            if (!isBugFix && int.TryParse(fiBacklogMesa.EstEffortDays, out int estEffortDays) && valueWithReq.Value.Fields.Effort != estEffortDays)
            {
                Update(workItemTrackingHttpClient, sync, valueWithReq);
                continue;
            }
            dateTime = GetCommitDate(fiBacklogMesa);
            if (dateTime is not null)
            {
                timeSpan = new(valueWithReq.Value.Fields.TargetDate.Ticks - dateTime.Value.Ticks);
                if (timeSpan.Hours is > 32 or < -32)
                {
                    Update(workItemTrackingHttpClient, sync, valueWithReq);
                    continue;
                }
            }
        }
    }

    private static string GetDescription(FIBacklogMesa fiBacklogMesa, DateTime dateTime) =>
        $"Req:{fiBacklogMesa.Req}; Submitted:{(dateTime == DateTime.MinValue ? fiBacklogMesa.Submitted : dateTime.ToString("d-MMM-yy"))}; Requestor:{fiBacklogMesa.Requestor}; AssignedTo:{fiBacklogMesa.AssignedTo}; SecondResource:{fiBacklogMesa.SecondResource}; Systems:{fiBacklogMesa.SystemS}; ";

    private static void Update(HttpClient httpClient, string basePage, string api, string query, HttpContent httpContent)
    {
#if CORE
        Task<HttpResponseMessage> httpResponseMessageTask = httpClient.PatchAsync(string.Concat(basePage, api, query), httpContent);
        httpResponseMessageTask.Wait();
        if (!httpResponseMessageTask.Result.IsSuccessStatusCode)
            throw new Exception(httpResponseMessageTask.Result.StatusCode.ToString());
        Task<string> stringTask = httpResponseMessageTask.Result.Content.ReadAsStringAsync();
        stringTask.Wait();
#endif
    }

    private static void UpdateIds(HttpClient httpClient, string basePage, string api, string[] checkFiles)
    {
        int? idIndex;
        string[] lines;
        string[] segments;
        string stringPayload;
        HttpContent httpContent;
        foreach (string checkFile in checkFiles)
        {
            idIndex = null;
            lines = File.ReadAllLines(checkFile);
            if (lines.Length < 1)
                continue;
            segments = lines.First().Split(',');
            for (int i = 0; i < segments.Length; i++)
            {
                if (segments[i] == "ID")
                {
                    idIndex = i;
                    break;
                }
            }
            if (idIndex is null)
                continue;
            for (int i = 1; i < lines.Length; i++)
            {
                segments = lines[i].Split(',');
                if (segments.Length < idIndex.Value)
                    continue;
                var payload = new
                {
                    op = "replace",
                    path = "/fields/System.IterationPath",
                    value = "Mesa_FI"
                };
                stringPayload = JsonSerializer.Serialize(payload);
                httpContent = new StringContent($"[{stringPayload}]", Encoding.UTF8, "application/json-patch+json");
                Update(httpClient, basePage, api, $"/workitems/{segments[idIndex.Value].Replace("\"", string.Empty)}?api-version=1.0", httpContent);
            }
        }
    }

    private static JsonPatchDocument GetUATDocument(string project, ReadOnlyDictionary<string, string> requestorNameToUser, DateTime dateTime, FIBacklogMesa fiBacklogMesa)
    {
        JsonPatchDocument result = new();
        AddPatch(result, "/fields/System.AreaPath", project);
        string description = GetDescription(fiBacklogMesa, dateTime);
        AddPatch(result, "/fields/System.IterationPath", project);
        AddPatch(result, "/fields/System.Title", $"{fiBacklogMesa.Req} - UAT");
        AddPatch(result, "/fields/System.Description", description);
        if (requestorNameToUser.TryGetValue(fiBacklogMesa.Requestor, out string? requestorUser))
            AddPatch(result, "/fields/System.AssignedTo", requestorUser);
        return result;
    }

    private static JsonPatchDocument GetBugDocument(string project, ReadOnlyDictionary<string, string> assignedToNameToUser, Task<WorkItem> uatWorkItemTask, FIBacklogMesa fiBacklogMesa)
    {
        JsonPatchDocument result = new();
        if (uatWorkItemTask.Result.Id is null)
            throw new NotSupportedException();
        AddPatch(result, "/relations/-", new WorkItemRelation() { Rel = "System.LinkTypes.Hierarchy-Forward", Url = uatWorkItemTask.Result.Url });
        AddPatch(result, "/fields/System.AreaPath", project);
        AddPatch(result, "/fields/System.IterationPath", project);
        AddPatch(result, "/fields/System.Title", $"{fiBacklogMesa.Req} - {fiBacklogMesa.Subject}");
        string? state = GetMappedState(fiBacklogMesa);
        if (!string.IsNullOrEmpty(state))
            AddPatch(result, "/fields/System.State", state);
        if (!string.IsNullOrEmpty(fiBacklogMesa.Definition))
            AddPatch(result, "/fields/System.Description", fiBacklogMesa.Definition);
        if (assignedToNameToUser.TryGetValue(fiBacklogMesa.Requestor, out string? requestorUser))
            AddPatch(result, "/fields/System.AssignedTo", requestorUser);
        return result;
    }

    private static JsonPatchDocument GetDeveloperTaskDocument(string project, ReadOnlyDictionary<string, string> assignedToNameToUser, FIBacklogMesa fiBacklogMesa)
    {
        JsonPatchDocument result = new();
        AddPatch(result, "/fields/System.AreaPath", project);
        AddPatch(result, "/fields/System.IterationPath", project);
        AddPatch(result, "/fields/System.Title", $"{fiBacklogMesa.Req} - Developer Task");
        if (assignedToNameToUser.TryGetValue(fiBacklogMesa.AssignedTo, out string? assignedToUser))
            AddPatch(result, "/fields/System.AssignedTo", assignedToUser);
        return result;
    }

    private static JsonPatchDocument GetSecondDeveloperTaskDocument(string project, ReadOnlyDictionary<string, string> assignedToNameToUser, FIBacklogMesa fiBacklogMesa)
    {
        JsonPatchDocument result = new();
        AddPatch(result, "/fields/System.AreaPath", project);
        AddPatch(result, "/fields/System.IterationPath", project);
        AddPatch(result, "/fields/System.Title", $"{fiBacklogMesa.Req} - Developer Task");
        if (assignedToNameToUser.TryGetValue(fiBacklogMesa.SecondResource, out string? secondResourceUser))
            AddPatch(result, "/fields/System.AssignedTo", secondResourceUser);
        return result;
    }

    private static JsonPatchDocument GetUserStoryDocument(string project, ReadOnlyDictionary<string, string> requestorNameToUser, Task<WorkItem> uatWorkItemTask, FIBacklogMesa fiBacklogMesa)
    {
        JsonPatchDocument result = new();
        if (uatWorkItemTask?.Result.Id is null)
            throw new NotSupportedException();
        AddPatch(result, "/relations/-", new WorkItemRelation() { Rel = "System.LinkTypes.Hierarchy-Forward", Url = uatWorkItemTask.Result.Url });
        AddPatch(result, "/fields/System.AreaPath", project);
        AddPatch(result, "/fields/System.IterationPath", project);
        AddPatch(result, "/fields/System.Title", $"{fiBacklogMesa.Req} - User Story");
        string? state = GetMappedState(fiBacklogMesa);
        if (!string.IsNullOrEmpty(state))
            AddPatch(result, "/fields/System.State", state);
        if (requestorNameToUser.TryGetValue(fiBacklogMesa.Requestor, out string? requestorUser))
            AddPatch(result, "/fields/System.AssignedTo", requestorUser);
        return result;
    }

    private static JsonPatchDocument GetAssignedToRelationDocument(Task<WorkItem> assignedToWorkItemTask)
    {
        JsonPatchDocument result = new();
        if (assignedToWorkItemTask.Result.Id is null)
            throw new NotSupportedException();
        AddPatch(result, "/relations/-", new WorkItemRelation() { Rel = "System.LinkTypes.Hierarchy-Forward", Url = assignedToWorkItemTask.Result.Url });
        return result;
    }

    private static JsonPatchDocument GetSecondResourceDocument(Task<WorkItem> secondResourceWorkItemTask)
    {
        JsonPatchDocument result = new();
        if (secondResourceWorkItemTask?.Result.Id is null)
            throw new NotSupportedException();
        AddPatch(result, "/relations/-", new WorkItemRelation() { Rel = "System.LinkTypes.Hierarchy-Forward", Url = secondResourceWorkItemTask.Result.Url });
        return result;
    }

    private static JsonPatchDocument GetFeatureDocument(string project, ReadOnlyDictionary<string, string> requestorNameToUser, List<string> tags, Task<WorkItem>? userStoryWorkItemTask, FIBacklogMesa fiBacklogMesa)
    {
        JsonPatchDocument result = new();
        if (userStoryWorkItemTask?.Result.Id is null)
            throw new NotSupportedException();
        string title = $"{fiBacklogMesa.Req} - {fiBacklogMesa.Subject}";
        if (title.Length > 128)
            title = title.Substring(0, 127);
        AddPatch(result, "/relations/-", new WorkItemRelation() { Rel = "System.LinkTypes.Hierarchy-Forward", Url = userStoryWorkItemTask.Result.Url });
        AddPatch(result, "/fields/System.AreaPath", project);
        if (tags.Count > 0)
        {
            AddPatch(result, "/fields/System.Tags", tags.Last());
            tags.RemoveAt(tags.Count - 1);
        }
        AddPatch(result, "/fields/System.IterationPath", project);
        if (!string.IsNullOrEmpty(fiBacklogMesa.Definition))
            AddPatch(result, "/fields/System.Description", fiBacklogMesa.Definition);
        string? state = GetMappedState(fiBacklogMesa);
        if (!string.IsNullOrEmpty(state))
            AddPatch(result, "/fields/System.State", state);
        if (int.TryParse(fiBacklogMesa.Priority.Substring(0, 1), out int priority) && priority != 0)
            AddPatch(result, "/fields/Microsoft.VSTS.Common.Priority", priority);
        if (!string.IsNullOrEmpty(fiBacklogMesa.EstEffortDays) && int.TryParse(fiBacklogMesa.EstEffortDays, out int estEffortDays) && estEffortDays != 0)
            AddPatch(result, "/fields/Microsoft.VSTS.Scheduling.Effort", estEffortDays);
        DateTime? dateTime = GetCommitDate(fiBacklogMesa);
        if (dateTime is not null)
            AddPatch(result, "/fields/Microsoft.VSTS.Scheduling.TargetDate", dateTime);
        if (!string.IsNullOrEmpty(fiBacklogMesa.Updates))
            AddPatch(result, "/fields/System.History", fiBacklogMesa.Updates);
        AddPatch(result, "/fields/System.Title", title);
        if (requestorNameToUser.TryGetValue(fiBacklogMesa.Requestor, out string? requestorUser))
            AddPatch(result, "/fields/System.AssignedTo", requestorUser);
        // https://tfs.intra.infineon.com/tfs/ManufacturingIT/Mesa_FI/_apis/wit/workitemtypes/feature/fields?api-version=7.0
        return result;
    }

    private static List<string> GetTags(FIBacklogMesa fiBacklogMesa)
    {
        List<string> results = new();
        foreach (string tag in fiBacklogMesa.SystemS.Split('/'))
        {
            if (string.IsNullOrEmpty(tag.Trim()))
                continue;
            results.Add(tag.Trim());
        }
        return results;
    }

    private static List<string> GetTags(Fields fields)
    {
        List<string> results = new();
        if (!string.IsNullOrEmpty(fields.SystemTags))
        {
            foreach (string tag in fields.SystemTags.Split(';'))
            {
                if (string.IsNullOrEmpty(tag.Trim()))
                    continue;
                results.Add(tag.Trim());
            }
        }
        return results;
    }

    private static void DoWork(WorkItemTrackingHttpClient workItemTrackingHttpClient, string project, ReadOnlyDictionary<string, string> assignedToNameToUser, ReadOnlyDictionary<string, string> requestorNameToUser, FIBacklogMesa fiBacklogMesa)
    {
        DateTime dateTime;
        JsonPatchDocument tagDocument;
        List<string> tags = GetTags(fiBacklogMesa);
        Task<WorkItem>? secondResourceWorkItemTask = null;
        bool isBugFix = fiBacklogMesa.Priority == "0 - BugFix";
        if (!DateTime.TryParse(fiBacklogMesa.Submitted, out dateTime))
            dateTime = DateTime.MinValue;
        JsonPatchDocument uatDocument = GetUATDocument(project, requestorNameToUser, dateTime, fiBacklogMesa);
        Task<WorkItem> uatWorkItemTask = workItemTrackingHttpClient.CreateWorkItemAsync(uatDocument, project, "Task");
        uatWorkItemTask.Wait();
        if (isBugFix)
        {
            JsonPatchDocument bugDocument = GetBugDocument(project, assignedToNameToUser, uatWorkItemTask, fiBacklogMesa);
            Task<WorkItem> bugWorkItemTask = workItemTrackingHttpClient.CreateWorkItemAsync(bugDocument, project, "Bug");
            bugWorkItemTask.Wait();
        }
        if (!isBugFix)
        {
            JsonPatchDocument developerTaskDocument = GetDeveloperTaskDocument(project, assignedToNameToUser, fiBacklogMesa);
            Task<WorkItem> assignedToWorkItemTask = workItemTrackingHttpClient.CreateWorkItemAsync(developerTaskDocument, project, "Task");
            assignedToWorkItemTask.Wait();
            if (!string.IsNullOrEmpty(fiBacklogMesa.SecondResource))
            {
                JsonPatchDocument secondDeveloperTaskDocument = GetSecondDeveloperTaskDocument(project, assignedToNameToUser, fiBacklogMesa);
                secondResourceWorkItemTask = workItemTrackingHttpClient.CreateWorkItemAsync(secondDeveloperTaskDocument, project, "Task");
                secondResourceWorkItemTask.Wait();
            }
            JsonPatchDocument userStoryDocument = GetUserStoryDocument(project, requestorNameToUser, uatWorkItemTask, fiBacklogMesa);
            Task<WorkItem> userStoryWorkItemTask = workItemTrackingHttpClient.CreateWorkItemAsync(userStoryDocument, project, "User Story");
            userStoryWorkItemTask.Wait();
            if (userStoryWorkItemTask?.Result.Id is null)
                throw new NotSupportedException();
            JsonPatchDocument assignedToRelationDocument = GetAssignedToRelationDocument(assignedToWorkItemTask);
            userStoryWorkItemTask = workItemTrackingHttpClient.UpdateWorkItemAsync(assignedToRelationDocument, userStoryWorkItemTask.Result.Id.Value);
            userStoryWorkItemTask.Wait();
            if (secondResourceWorkItemTask is not null)
            {
                if (userStoryWorkItemTask.Result.Id is null)
                    throw new NotSupportedException();
                JsonPatchDocument secondResourceDocument = GetSecondResourceDocument(secondResourceWorkItemTask);
                userStoryWorkItemTask = workItemTrackingHttpClient.UpdateWorkItemAsync(secondResourceDocument, userStoryWorkItemTask.Result.Id.Value);
                userStoryWorkItemTask.Wait();
            }
            JsonPatchDocument featureDocument = GetFeatureDocument(project, requestorNameToUser, tags, userStoryWorkItemTask, fiBacklogMesa);
            Task<WorkItem> featureWorkItemTask = workItemTrackingHttpClient.CreateWorkItemAsync(featureDocument, project, "Feature");
            featureWorkItemTask.Wait();
            for (int i = tags.Count - 1; i > -1; i--)
            {
                if (featureWorkItemTask.Result.Id is null)
                    throw new NotSupportedException();
                tagDocument = new();
                AddPatch(tagDocument, "/fields/System.Tags", tags[i]);
                tags.RemoveAt(i);
                featureWorkItemTask = workItemTrackingHttpClient.UpdateWorkItemAsync(tagDocument, featureWorkItemTask.Result.Id.Value);
                featureWorkItemTask.Wait();
            }
        }
    }

    private void Parse(IFileRead fileRead, Logistics logistics, List<FileInfo> fileInfoCollection, HttpClient httpClient, string basePage, string api, string query, WorkItemTrackingHttpClient workItemTrackingHttpClient, string project, ReadOnlyDictionary<string, string> assignedToNameToUser, ReadOnlyDictionary<string, string> requestorNameToUser, string json)
    {
        if (fileRead is null)
            throw new NullReferenceException();
        if (logistics is null)
            throw new NullReferenceException();
        if (fileInfoCollection is null)
            throw new NullReferenceException();
        int counter = 0;
        string? directory = Path.GetDirectoryName(fileRead.ReportFullPath) ?? throw new Exception();
        string[] checkFiles = Directory.GetFiles(directory, "*.csv", SearchOption.TopDirectoryOnly);
        if (checkFiles.Any())
            UpdateIds(httpClient, basePage, api, checkFiles);
        else
        {
            string ids = GetIds(httpClient, basePage, api, query);
            Dictionary<string, FIBacklogMesa> keyToFIBacklogMesa = GetFIBacklogMesaCollection(json);
            Value[] workItems = string.IsNullOrEmpty(ids) ? Array.Empty<Value>() : GetWorkItems(httpClient, basePage, api, ids);
            int count = keyToFIBacklogMesa.Count;
            ReadOnlyCollection<ValueWithReq> valueWithReqCollection = GetValueWithReqCollection(workItems);
            SetSyncTag(workItemTrackingHttpClient, requestorNameToUser, keyToFIBacklogMesa, valueWithReqCollection);
            ReadOnlyCollection<ValueWithReq> extra = RemoveFrom(keyToFIBacklogMesa, valueWithReqCollection);
            if (count != extra.Count)
            { }
            if (count != keyToFIBacklogMesa.Count)
            { }
            _Details.AddRange(workItems);
            foreach (KeyValuePair<string, FIBacklogMesa> keyValuePair in keyToFIBacklogMesa)
            {
                if (counter > 5)
                    break;
                if (!fileRead.IsEAFHosted)
                    continue;
                DoWork(workItemTrackingHttpClient, project, assignedToNameToUser, requestorNameToUser, keyValuePair.Value);
                counter++;
            }
        }
    }

}