using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

using C4IT.FASD.Base;
using FasdCockpitCommunicationDemo;
using static C4IT.Logging.cLogManager;

using Microsoft.Office.Interop.Excel;
using Excel = Microsoft.Office.Interop.Excel;
using System.Windows.Shapes;
using System.Text.RegularExpressions;
using FasdCockpitBase.Models;

namespace FasdExcelToJsonConverter
{
    public class cExcelHealthcardParser
    {
        private Dictionary<string, Worksheet> workSheets;

        public cExcelHealthcardParser(Workbook selectedWorkBook)
        {
            if (LoadWorkSheets(selectedWorkBook, out var workSheets))
                this.workSheets = workSheets;
        }

        private bool LoadWorkSheets(Workbook selectedWorkBook, out Dictionary<string, Worksheet> workSheets)
        {
            var CM = MethodBase.GetCurrentMethod();
            LogMethodBegin(CM);

            workSheets = new Dictionary<string, Worksheet>();
            if (selectedWorkBook == null)
                return false;

            try
            {
                foreach (Worksheet workSheet in selectedWorkBook.Worksheets)
                {
                    workSheets.Add(workSheet.Name, workSheet);
                }

                return true;
            }
            catch (Exception E)
            {
                LogException(E);
            }
            finally
            {
                LogMethodEnd(CM);
            }

            return false;
        }

        public bool GetHealthcardDataFromExcel(string WorkSheetName, out cF4SDHealthCardJsonRawData HealthcardJsonData)
        {
            var CM = MethodBase.GetCurrentMethod();
            LogMethodBegin(CM);

            HealthcardJsonData = new cF4SDHealthCardJsonRawData();
            if (string.IsNullOrEmpty(WorkSheetName))
                return false;

            try
            {
                if (!workSheets.TryGetValue(WorkSheetName, out var selectedWorkSheet))
                    return false;

                var range = selectedWorkSheet.UsedRange;
                var healthCardData = new cF4SDHealthCardRawData();

                for (int excelRow = 2; excelRow <= range.Rows.Count; excelRow++) // start from 2 because not zero based and 1st row contains header
                {
                    //Get values of excel row
                    var values = new List<object>();
                    for (int excelColumn = 3; excelColumn <= range.Columns.Count; excelColumn++) // start from 2 because not zero based and 1st and 2nd column contains ValueTable & ValueColumn
                    {
                        var cellValue = range.Cells[excelRow, excelColumn].Value as object;
                        values.Add(cellValue);
                    }

                    //Get Table of Dictionary
                    var valueTable = range.Cells[excelRow, 1].Value?.ToString();
                    if (!healthCardData.Tables.ContainsKey(valueTable))
                        healthCardData.Tables.Add(valueTable, new cF4SDHealthCardRawData.cHealthCardTable() { Name = valueTable });

                    //Add Columns
                    if (healthCardData.Tables.TryGetValue(valueTable, out cF4SDHealthCardRawData.cHealthCardTable tableDictionaryEntry))
                    {
                        var columnName = range.Cells[excelRow, 2].Value?.ToString();
                        if (tableDictionaryEntry.Columns.ContainsKey(columnName))
                            continue;

                        tableDictionaryEntry.Columns.Add(columnName, new cF4SDHealthCardRawData.cHealthCardTableColumn(tableDictionaryEntry) { ColumnName = columnName, Values = values.ToList() });

                        if (tableDictionaryEntry.TimeFrames == null)
                            tableDictionaryEntry.TimeFrames = new DateTime[1, 2];

                        if (tableDictionaryEntry.TimeFrames.GetLength(0) < values.Count)
                            tableDictionaryEntry.TimeFrames = new DateTime[values.Count, 2];
                    }
                }

                foreach (var table in healthCardData.Tables)
                {
                    table.Value.TimeFrames[0, 0] = DateTime.Now;
                    table.Value.TimeFrames[0, 1] = DateTime.Today;

                    for (int i = 1; i < table.Value.TimeFrames.GetLength(0) - 1; i++)
                    {
                        table.Value.TimeFrames[i, 0] = DateTime.Today.AddDays(-i);
                        table.Value.TimeFrames[i, 1] = DateTime.Today.AddDays(-i - 1);
                    }
                }

                HealthcardJsonData = cF4SDHealthCardJsonRawData.GetHealthCardJsonRawData(healthCardData);
                HealthcardJsonData.DetailsTables = GetDetailsTablesFromExcel();

                HealthcardJsonData.Tickets = GetTicketsFromExcel();

                return true;
            }
            catch (Exception E)
            {
                LogException(E);
            }
            finally
            {
                LogMethodEnd(CM);
            }

            return false;
        }

        private List<cF4SDHealthCardRawData.cHealthCardDetailsTable> GetDetailsTablesFromExcel()
        {
            var CM = MethodBase.GetCurrentMethod();
            LogMethodBegin(CM);

            var output = new List<cF4SDHealthCardRawData.cHealthCardDetailsTable>();

            try
            {
                foreach (var workSheet in workSheets)
                {
                    if (!workSheet.Key.StartsWith("details-"))
                        continue;

                    var selectedWorkSheet = workSheet.Value;
                    var range = selectedWorkSheet.UsedRange;

                    var tableName = workSheet.Key.Replace("details-", "agnt-computer-event-details-");

                    var tableColumns = new List<string>();
                    for (int i = 2; i <= range.Columns.Count; i++)
                    {
                        tableColumns.Add(range.Cells[1, i].Value?.ToString());
                    }

                    var tableValues = new Dictionary<int, List<object[]>>();

                    for (int excelRow = 2; excelRow <= range.Rows.Count; excelRow++)
                    {
                        var dayValue = range.Cells[excelRow, 1].Value?.ToString();
                        int dayIndex = int.MinValue;

                        if (DateTime.TryParse(dayValue, out DateTime dayDate))
                            dayIndex = (DateTime.Today - dayDate).Days;

                        List<object> rowValues = new List<object>();

                        for (int excelColumn = 2; excelColumn <= range.Columns.Count; excelColumn++)
                        {
                            rowValues.Add(range.Cells[excelRow, excelColumn].Value);
                        }

                        if (tableValues.TryGetValue(dayIndex, out var dayValues))
                            dayValues.Add(rowValues.ToArray());
                        else
                            tableValues.Add(dayIndex, new List<object[]>() { rowValues.ToArray() });
                    }

                    var tableToAdd = new cF4SDHealthCardRawData.cHealthCardDetailsTable() { Name = tableName, Columns = tableColumns, Values = tableValues };

                    output.Add(tableToAdd);
                }
            }
            catch (Exception E)
            {
                LogException(E);
            }
            finally
            {
                LogMethodEnd(CM);
            }

            return output;
        }

        private List<cF4SDTicket> GetTicketsFromExcel()
        {
            var CM = MethodBase.GetCurrentMethod();
            LogMethodBegin(CM);

            List<cF4SDTicket> output = new List<cF4SDTicket>();

            try
            {
                if (!workSheets.TryGetValue("%TicketData%", out var TicketWorksheet))
                    return output;

                Dictionary<double, cF4SDTicket> tempTickets = new Dictionary<double, cF4SDTicket>();

                var ticketRange = TicketWorksheet.UsedRange;
                for (int row = 2; row <= ticketRange.Rows.Count; row++)
                {
                    double ticketId = ticketRange.Cells[row, 1].Value;
                    string affectedUser = ticketRange.Cells[row, 2].Value;
                    double creationDaysSinceNow = ticketRange.Cells[row, 3].Value;
                    DateTime creationDate = DateTime.Now.AddDays(-creationDaysSinceNow);
                    double? closingDaysSinceNow = ticketRange.Cells[row, 4].Value;

                    DateTime? closingDate = null;
                    if (closingDaysSinceNow.HasValue)
                        closingDate = DateTime.Now.AddDays(closingDaysSinceNow.Value);
                    enumTicketStatus ticketStatus = enumTicketStatus.Unknown;
                    Enum.TryParse<enumTicketStatus>(ticketRange.Cells[row, 5].Value?.ToString(), out ticketStatus);
                    cF4SDTicket.enumTicketCreationSource creationSource = cF4SDTicket.enumTicketCreationSource.Unknown;
                    Enum.TryParse<cF4SDTicket.enumTicketCreationSource>(ticketRange.Cells[row, 6].Value, out creationSource);
                    // classification = ticketRange.Cells[row, 7].Value;
                    string asset = ticketRange.Cells[row, 8].Value;
                    string ticketName = ticketRange.Cells[row, 9].Value;
                    string summary = ticketRange.Cells[row, 10].Value;
                    string category = ticketRange.Cells[row, 11].Value;
                    double priority = ticketRange.Cells[row, 12].Value;
                    string description = ticketRange.Cells[row, 13].Value;
                    string htmlDescription = ticketRange.Cells[row, 14].Value;
                    string solution = ticketRange.Cells[row, 15].Value;
                    string directLinkPreview = ticketRange.Cells[row, 16].Value;
                    string directLinkEdit = ticketRange.Cells[row, 17].Value;
                    string directLinkClose = ticketRange.Cells[row, 18].Value;

                    if (tempTickets.ContainsKey(ticketId))
                    {
                        LogEntry($"Ticket with id {ticketId} allready exists.");
                        continue;
                    }

                    cF4SDTicket tempTicket = new cF4SDTicket()
                    {
                        Id = Guid.NewGuid(),
                        AffectedUser = affectedUser,
                        CreationDaysSinceNow = creationDaysSinceNow,
                        CreationDate = creationDate,
                        ClosingDaysSinceNow = closingDaysSinceNow,
                        ClosingDate = closingDate,
                        Status = ticketStatus,
                        CreationSource = creationSource,
                        Asset = asset,
                        Name = ticketName,
                        Summary = summary,
                        Category = category,
                        Priority = (int)priority,
                        Description = description,
                        DescriptionHtml = htmlDescription,
                        Solution = solution,
                        JournalItems = new List<cF4SDTicket.cTicketJournalItem>(),
                        DirectLinks = new Dictionary<string, string>()
                    };

                    if (!(string.IsNullOrWhiteSpace(directLinkPreview)))
                    {
                        tempTicket.DirectLinks.Add("DirectLinkPreview", directLinkPreview);

                        var ticketIdString = Regex.Match(directLinkPreview, @"[0-9A-Fa-f]{8}-?([0-9A-Fa-f]{4}-?){3}[0-9A-Fa-f]{12}");
                        if (ticketIdString.Success && Guid.TryParse(ticketIdString.Value, out var tempTicketId))
                            tempTicket.Id = tempTicketId;
                    }

                    if (!(string.IsNullOrWhiteSpace(directLinkEdit)))
                        tempTicket.DirectLinks.Add("DirectLinkEdit", directLinkEdit);

                    if (!(string.IsNullOrWhiteSpace(directLinkClose)))
                        tempTicket.DirectLinks.Add("DirectLinkClose", directLinkClose);

                    tempTickets.Add(ticketId, tempTicket);
                }

                output = tempTickets.Values.ToList();

                if (!workSheets.TryGetValue("%TicketDetails%", out var DetailsWorksheet))
                    return output;

                var detailRange = DetailsWorksheet.UsedRange;

                for (int row = 2; row <= detailRange.Rows.Count; row++)
                {
                    double ticketId = detailRange.Cells[row, 1].Value;
                    double creationDaysSinceNow = detailRange.Cells[row, 2].Value;
                    DateTime creationDate = DateTime.Now.AddDays(-creationDaysSinceNow);
                    bool isVisibleForUser = bool.Parse(detailRange.Cells[row, 3].Value);
                    string header = detailRange.Cells[row, 4].Value;
                    string createdBy = detailRange.Cells[row, 5].Value;
                    string description = detailRange.Cells[row, 6].Value;

                    var tempJournalItem = new cF4SDTicket.cTicketJournalItem()
                    {
                        CreationDaysSinceNow = creationDaysSinceNow,
                        CreationDate = creationDate,
                        IsVisibleForUser = isVisibleForUser,
                        Header = header,
                        CreatedBy = createdBy,
                        Description = description
                    };

                    if (tempTickets.ContainsKey(ticketId))
                    {
                        var tempJournalItems = tempTickets[ticketId].JournalItems;
                        if (tempJournalItems is null)
                            tempJournalItems = new List<cF4SDTicket.cTicketJournalItem>();

                        tempJournalItems.Add(tempJournalItem);
                    }
                }

                output = tempTickets.Values.ToList();
            }
            catch (Exception E)
            {
                LogException(E);
            }
            finally
            {
                LogMethodEnd(CM);
            }

            return output;
        }
    }
}
