using Microsoft.Extensions.Logging;
using System.Collections.ObjectModel;
using System.Text.Json;
using System.Text.Json.Serialization;

namespace File_Folder_Helper.ADO2024.PI3;

internal static partial class Helper20240822
{

    private record Record(string? Title, ReadOnlyCollection<string> Tags, string? Completed);

    private record Root([property: JsonPropertyName("headings")] Heading[] Headings,
                         [property: JsonPropertyName("lanes")] Lane[] Lanes);

    [JsonSourceGenerationOptions(WriteIndented = true)]
    [JsonSerializable(typeof(Root))]
    private partial class Helper20240822RootSourceGenerationContext : JsonSerializerContext
    {
    }

    private record Welcome2([property: JsonPropertyName("headings")] Heading[] Headings,
                             [property: JsonPropertyName("lanes")] Lane[] Lanes);

    private record Heading([property: JsonPropertyName("name")] string Name,
                            [property: JsonPropertyName("heading")] string HeadingHeading);

    private record Lane([property: JsonPropertyName("name")] string Name,
                         [property: JsonPropertyName("columns")] Column[][] Columns);

    private record Column([property: JsonPropertyName("id")] string Id,
                           [property: JsonPropertyName("name")] string Name,
                           [property: JsonPropertyName("description")] string Description,
                           [property: JsonPropertyName("metadata")] Metadata? Metadata,
                           [property: JsonPropertyName("subTasks")] SubTask[]? SubTasks,
                           [property: JsonPropertyName("relations")] object[] Relations,
                           [property: JsonPropertyName("comments")] Comment[] Comments,
                           [property: JsonPropertyName("column")] string ColumnColumn,
                           [property: JsonPropertyName("workload")] long Workload,
                           [property: JsonPropertyName("progress")] long Progress,
                           [property: JsonPropertyName("remainingWorkload")] long RemainingWorkload,
                           [property: JsonPropertyName("dueData")] DueData DueData);

    private record Comment([property: JsonPropertyName("text")] string Text,
                            [property: JsonPropertyName("date")] DateTimeOffset Date);

    private record DueData([property: JsonPropertyName("completed")] bool Completed,
                            [property: JsonPropertyName("completedDate")] object CompletedDate,
                            [property: JsonPropertyName("dueDate")] DateTimeOffset DueDate,
                            [property: JsonPropertyName("overdue")] bool Overdue,
                            [property: JsonPropertyName("dueDelta")] long DueDelta,
                            [property: JsonPropertyName("dueMessage")] string DueMessage);

    private record Metadata([property: JsonPropertyName("assigned")] string Assigned,
                             [property: JsonPropertyName("created")] DateTimeOffset Created,
                             [property: JsonPropertyName("progress")] long? Progress,
                             [property: JsonPropertyName("started")] DateTimeOffset? Started,
                             [property: JsonPropertyName("status")] string? Status,
                             [property: JsonPropertyName("tags")] string[]? Tags,
                             [property: JsonPropertyName("type")] string? Type,
                             [property: JsonPropertyName("updated")] DateTimeOffset Updated,
                             [property: JsonPropertyName("due")] DateTimeOffset? Due,
                             [property: JsonPropertyName("completed")] DateTimeOffset? Completed);

    private record SubTask([property: JsonPropertyName("text")] string Text,
                            [property: JsonPropertyName("completed")] bool Completed);

    private static ReadOnlyCollection<ReadOnlyCollection<Record>> GetRecords(Column[][] columnCollection)
    {
        List<ReadOnlyCollection<Record>> results = [];
        bool check;
        int subTasks;
        Column column;
        int completed;
        List<Record> row;
        string? subtasks;
        List<string> tags;
        for (int i = 0; i < int.MaxValue; i++)
        {
            row = [];
            check = false;
            foreach (Column[] columns in columnCollection)
            {
                if (columns.Length <= i)
                    row.Add(new(null, new([]), null));
                else
                {
                    tags = [];
                    subTasks = 0;
                    completed = 0;
                    column = columns[i];
                    if (!check)
                        check = true;
                    if (column.Metadata?.Tags is not null && column.Metadata.Tags.Length != 0)
                    {
                        foreach (string tag in column.Metadata.Tags)
                            tags.Add(tag);
                    }
                    if (column.SubTasks is not null && column.SubTasks.Length != 0)
                    {
                        foreach (SubTask subTask in column.SubTasks)
                        {
                            subTasks += 1;
                            if (subTask.Completed)
                                completed += 1;
                        }
                    }
                    subtasks = subTasks == 0 ? subtasks = null : $"{completed} / {subTasks}";
                    row.Add(new(column.Name, new(tags), subtasks));
                }
            }
            if (!check)
                break;
            if (results.Count > 0)
            {
                if (results[0].Count != row.Count)
                    throw new Exception("Rows must match!");
            }
            results.Add(new(row));
        }
        return new(results);
    }

    private static void WriteFile(string destinationFile, Heading[] headings, ReadOnlyCollection<ReadOnlyCollection<Record>> recordCollection)
    {
        string title;
        string completed;
        List<string> lines =
        [
            "<html>",
            "<head>",
            "<style>",
            ":root {",
            "color-scheme: light dark;",
            "}",
            "body {",
            "color: light-dark(#333b3c, #efedea);",
            "background-color: light-dark(#efedea, #333b3c);",
            "}",
            "td {",
            "vertical-align: top;",
            "}",
            ".title {",
            "font-weight: bold;",
            "}",
            ".complete {",
            "font-size: small;",
            "}",
            ".speech-bubble {",
            "position: relative;",
            "background: darkCyan;",
            "border-radius: .4em;",
            "}",
            ".speech-bubble:after {",
            "content: '';",
            "position: absolute;",
            "bottom: 0;",
            "left: 50%;",
            "width: 0;",
            "height: 0;",
            "border: 2px solid transparent;",
            "border-top-color: #00aabb;",
            "border-bottom: 0;",
            "margin-left: -2px;",
            "margin-bottom: -2px;",
            "}",
            "</style>",
            "</head>",
            "<table border=\"1\">",
            "<tr>"
        ];
        foreach (Heading heading in headings)
            lines.Add($"<th>{heading.Name}</th>");
        lines.Add("</tr>");
        foreach (ReadOnlyCollection<Record> records in recordCollection)
        {
            lines.Add("<tr>");
            foreach (Record record in records)
            {
                lines.Add("<td>");
                title = record.Title is null ? "&nbsp;" : record.Title;
                completed = record.Completed is null ? "&nbsp;" : record.Completed;
                lines.Add($"<div class=\"title\">{title}</div>");
                lines.Add("<div>");
                foreach (string tag in record.Tags)
                    lines.Add($"<span class=\"speech-bubble\">{tag}</span>");
                lines.Add("</div>");
                lines.Add($"<div class=\"completed\">{completed}</div>");
                lines.Add("</td>");
            }
            lines.Add("</tr>");
        }
        lines.Add("</table>");
        lines.Add("</html>");
        File.WriteAllLines(destinationFile, lines);
    }

    private static void ParseKanbn(ILogger<Worker> logger, string destinationFile, string json)
    {
        Root? root = JsonSerializer.Deserialize(json, Helper20240822RootSourceGenerationContext.Default.Root);
        if (root is null)
            logger.LogInformation("<{root}> is null!", root);
        else if (root.Lanes.Length != 1)
            logger.LogInformation("{root.Lanes} != 1", root.Lanes.Length);
        else if (root.Lanes[0].Columns.Length != root.Headings.Length)
            logger.LogInformation("{root[0].Columns.Lanes} != {root.Headings}", root.Lanes[0].Columns.Length, root.Headings.Length);
        else
        {
            ReadOnlyCollection<ReadOnlyCollection<Record>> recordCollection = GetRecords(root.Lanes[0].Columns);
            WriteFile(destinationFile, root.Headings, recordCollection);
        }
    }

    internal static void ParseKanbn(ILogger<Worker> logger, List<string> args)
    {
        string sourceDirectory = Path.GetFullPath(args[0]);
        string sourceFile = Path.Combine(sourceDirectory, args[2]);
        string destinationFile = Path.Combine(sourceDirectory, $"{DateTime.Now.Ticks}-{args[3]}");
        if (!File.Exists(sourceFile))
            logger.LogInformation("<{sourceFile}> doesn't exist!", sourceFile);
        else
        {
            string json = File.ReadAllText(sourceFile);
            ParseKanbn(logger, destinationFile, json);
        }
    }

}