namespace Journal.Core.Models;

public class JournalEntry
{
    public string Date { get; set; }
    public List<Fragment> Fragments { get; set; }
    public string RawContent { get; set; }
    public Dictionary<string, ParsedSection> Sections { get; set; }

    public JournalEntry(
        string date,
        IEnumerable<Fragment>? fragments = null,
        string rawContent = "",
        IDictionary<string, ParsedSection>? sections = null)
    {
        if (string.IsNullOrWhiteSpace(date))
            throw new ArgumentException("Date is required", nameof(date));

        Date = date.Trim();
        Fragments = fragments is null ? [] : [.. fragments];
        RawContent = rawContent ?? "";
        Sections = sections is null ? [] : new Dictionary<string, ParsedSection>(sections);
    }

    public string GetSection(string sectionTitle)
    {
        if (string.IsNullOrWhiteSpace(sectionTitle))
            return "";
        if (!Sections.TryGetValue(sectionTitle, out var section))
            return "";
        return string.Join("\n", section.Content);
    }

    public bool? GetCheckboxState(string sectionTitle, string checkboxText)
    {
        if (string.IsNullOrWhiteSpace(sectionTitle) || string.IsNullOrWhiteSpace(checkboxText))
            return null;
        if (!Sections.TryGetValue(sectionTitle, out var section))
            return null;
        return section.Checkboxes.TryGetValue(checkboxText, out var checkedState) ? checkedState : null;
    }

    public void MergeWith(JournalEntry otherEntry)
    {
        ArgumentNullException.ThrowIfNull(otherEntry);

        foreach (var (title, newSection) in otherEntry.Sections)
        {
            if (newSection.Content.Any(line => !string.IsNullOrWhiteSpace(line)))
                Sections[title] = newSection;
        }

        var existingFragmentDescriptions = Fragments
            .Select(fragment => fragment.Description)
            .ToHashSet(StringComparer.Ordinal);

        foreach (var newFragment in otherEntry.Fragments)
        {
            if (!existingFragmentDescriptions.Contains(newFragment.Description))
                Fragments.Add(newFragment);
        }
    }

    public string ToMarkdown()
    {
        var lines = new List<string>
        {
            "---",
            "type: journal",
            "---",
            $"**Date:** {Date}\n"
        };

        foreach (var title in SectionTitles.Canonical)
        {
            if (!Sections.TryGetValue(title, out var section))
                continue;

            lines.Add($"## {section.Title}\n");
            lines.AddRange(section.Content);
            lines.Add("");
        }

        if (Fragments.Count > 0)
        {
            lines.Add("# Fragments\n");
            foreach (var fragment in Fragments)
            {
                var timeStr = fragment.Time != default ? $"@{fragment.Time:O}" : "";
                var tagsStr = string.Join(" ", fragment.Tags.Select(tag => $"#{tag}"));
                var header = $"{fragment.Type} {timeStr} {tagsStr}".Trim();
                lines.Add($"{header}\n{fragment.Description}\n");
            }
        }

        return string.Join("\n", lines);
    }
}
