using System.Text.Json;
using System.Text.Json.Serialization;

namespace JobTrackerApi.Models;

public static class TailoredCvDraftJson
{
    private static readonly JsonSerializerOptions SerializerOptions = new(JsonSerializerDefaults.Web)
    {
        PropertyNameCaseInsensitive = true,
        DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
    };

    public static TailoredCvDocument Empty() => Normalize(new TailoredCvDocument());

    public static TailoredCvDocument FromDraft(TailoredCvDraft? draft)
    {
        if (draft is null) return Empty();

        var document = new TailoredCvDocument
        {
            TemplateId = string.IsNullOrWhiteSpace(draft.TemplateId) ? "base" : draft.TemplateId.Trim(),
            Headline = TrimOrNull(draft.Headline),
            Summary = DeserializeList(draft.SummaryJson),
            SelectedSkills = DeserializeList(draft.SelectedSkillsJson),
            Experience = DeserializeList<TailoredCvExperienceItem>(draft.ExperienceJson)
                .Select(NormalizeExperience)
                .Where(item => !string.IsNullOrWhiteSpace(item.Title) || !string.IsNullOrWhiteSpace(item.Company) || item.Bullets.Count > 0)
                .ToList(),
            Education = DeserializeList<TailoredCvEducationItem>(draft.EducationJson)
                .Select(NormalizeEducation)
                .Where(item => !string.IsNullOrWhiteSpace(item.Qualification) || !string.IsNullOrWhiteSpace(item.Institution) || item.Details.Count > 0)
                .ToList(),
            CustomSections = DeserializeList<TailoredCvCustomSection>(draft.CustomSectionsJson)
                .Select(NormalizeCustomSection)
                .Where(item => !string.IsNullOrWhiteSpace(item.Title) || item.Items.Count > 0)
                .ToList(),
            RenderOptions = DeserializeObject<TailoredCvRenderOptions>(draft.RenderOptionsJson) ?? new TailoredCvRenderOptions(),
        };

        return Normalize(document);
    }

    public static void ApplyToDraft(TailoredCvDraft draft, TailoredCvDocument? document)
    {
        var normalized = Normalize(document);
        draft.TemplateId = normalized.TemplateId;
        draft.Headline = TrimOrNull(normalized.Headline);
        draft.SummaryJson = JsonSerializer.Serialize(normalized.Summary, SerializerOptions);
        draft.SelectedSkillsJson = JsonSerializer.Serialize(normalized.SelectedSkills, SerializerOptions);
        draft.ExperienceJson = JsonSerializer.Serialize(normalized.Experience, SerializerOptions);
        draft.EducationJson = JsonSerializer.Serialize(normalized.Education, SerializerOptions);
        draft.CustomSectionsJson = JsonSerializer.Serialize(normalized.CustomSections, SerializerOptions);
        draft.RenderOptionsJson = JsonSerializer.Serialize(normalized.RenderOptions, SerializerOptions);
    }

    public static TailoredCvDocument Normalize(TailoredCvDocument? document)
    {
        document ??= new TailoredCvDocument();
        document.TemplateId = string.IsNullOrWhiteSpace(document.TemplateId) ? "ats-minimal" : document.TemplateId.Trim();
        document.Headline = TrimOrNull(document.Headline);
        document.Summary = CleanList(document.Summary);
        document.SelectedSkills = CleanList(document.SelectedSkills);
        document.Experience = (document.Experience ?? new List<TailoredCvExperienceItem>())
            .Select(NormalizeExperience)
            .Where(item => !string.IsNullOrWhiteSpace(item.Title) || !string.IsNullOrWhiteSpace(item.Company) || item.Bullets.Count > 0)
            .ToList();
        document.Education = (document.Education ?? new List<TailoredCvEducationItem>())
            .Select(NormalizeEducation)
            .Where(item => !string.IsNullOrWhiteSpace(item.Qualification) || !string.IsNullOrWhiteSpace(item.Institution) || item.Details.Count > 0)
            .ToList();
        document.CustomSections = (document.CustomSections ?? new List<TailoredCvCustomSection>())
            .Select(NormalizeCustomSection)
            .Where(item => !string.IsNullOrWhiteSpace(item.Title) || item.Items.Count > 0)
            .ToList();
        document.RenderOptions ??= new TailoredCvRenderOptions();
        document.RenderOptions.PageMode = string.IsNullOrWhiteSpace(document.RenderOptions.PageMode) ? "one-page" : document.RenderOptions.PageMode.Trim();
        document.RenderOptions.AccentColor = string.IsNullOrWhiteSpace(document.RenderOptions.AccentColor) ? "slate" : document.RenderOptions.AccentColor.Trim();
        document.RenderOptions.BulletDensity = string.IsNullOrWhiteSpace(document.RenderOptions.BulletDensity) ? "balanced" : document.RenderOptions.BulletDensity.Trim();
        document.RenderOptions.SectionOrder = CleanList(document.RenderOptions.SectionOrder);
        if (document.RenderOptions.SectionOrder.Count == 0)
        {
            document.RenderOptions.SectionOrder = new List<string> { "summary", "skills", "experience", "education", "custom" };
        }
        return document;
    }

    public static string RenderPlainText(TailoredCvDocument? document)
    {
        var normalized = Normalize(document);
        var lines = new List<string>();

        AddLine(lines, normalized.Headline);
        if (normalized.Summary.Count > 0)
        {
            AddBlock(lines, "Professional Summary", normalized.Summary.Select(item => $"- {item}"));
        }

        if (normalized.SelectedSkills.Count > 0)
        {
            AddBlock(lines, "Core Skills", normalized.SelectedSkills);
        }

        if (normalized.Experience.Count > 0)
        {
            var block = new List<string>();
            foreach (var item in normalized.Experience)
            {
                AddLine(block, item.Title);
                var meta = string.Join(" | ", new[]
                {
                    item.Company,
                    item.Location,
                    FormatDateRange(item.Start, item.End, item.IsCurrent)
                }.Where(value => !string.IsNullOrWhiteSpace(value)));
                AddLine(block, meta);
                foreach (var bullet in item.Bullets)
                {
                    AddLine(block, $"- {bullet}");
                }
                AddLine(block, string.Empty);
            }
            AddBlock(lines, "Experience", block);
        }

        if (normalized.Education.Count > 0)
        {
            var block = new List<string>();
            foreach (var item in normalized.Education)
            {
                AddLine(block, string.IsNullOrWhiteSpace(item.QualificationLevel) ? item.Qualification : $"{item.Qualification} ({item.QualificationLevel})");
                var meta = string.Join(" | ", new[]
                {
                    item.Institution,
                    item.Location,
                    FormatDateRange(item.Start, item.End, false)
                }.Where(value => !string.IsNullOrWhiteSpace(value)));
                AddLine(block, meta);
                foreach (var detail in item.Details)
                {
                    AddLine(block, $"- {detail}");
                }
                AddLine(block, string.Empty);
            }
            AddBlock(lines, "Education", block);
        }

        foreach (var section in normalized.CustomSections)
        {
            AddBlock(lines, section.Title ?? "Additional Information", section.Items);
        }

        return string.Join("\n\n", lines.Where(line => !string.IsNullOrWhiteSpace(line)).Select(line => line.Trim())).Trim();
    }

    private static TailoredCvExperienceItem NormalizeExperience(TailoredCvExperienceItem? item)
    {
        item ??= new TailoredCvExperienceItem();
        item.Title = TrimOrNull(item.Title);
        item.Company = TrimOrNull(item.Company);
        item.Location = TrimOrNull(item.Location);
        item.Start = TrimOrNull(item.Start);
        item.End = TrimOrNull(item.End);
        item.Bullets = CleanList(item.Bullets);
        item.IsCurrent = item.IsCurrent || string.Equals(item.End, "present", StringComparison.OrdinalIgnoreCase) || string.Equals(item.End, "current", StringComparison.OrdinalIgnoreCase);
        return item;
    }

    private static TailoredCvEducationItem NormalizeEducation(TailoredCvEducationItem? item)
    {
        item ??= new TailoredCvEducationItem();
        item.Qualification = TrimOrNull(item.Qualification);
        item.QualificationLevel = TrimOrNull(item.QualificationLevel);
        item.Institution = TrimOrNull(item.Institution);
        item.Location = TrimOrNull(item.Location);
        item.Start = TrimOrNull(item.Start);
        item.End = TrimOrNull(item.End);
        item.Details = CleanList(item.Details);
        return item;
    }

    private static TailoredCvCustomSection NormalizeCustomSection(TailoredCvCustomSection? item)
    {
        item ??= new TailoredCvCustomSection();
        item.Title = TrimOrNull(item.Title);
        item.Items = CleanList(item.Items);
        return item;
    }

    private static List<string> DeserializeList(string? json)
    {
        return DeserializeList<string>(json)
            .Select(value => value?.Trim() ?? string.Empty)
            .Where(value => !string.IsNullOrWhiteSpace(value))
            .Distinct(StringComparer.OrdinalIgnoreCase)
            .ToList();
    }

    private static List<T> DeserializeList<T>(string? json)
    {
        try
        {
            return string.IsNullOrWhiteSpace(json)
                ? new List<T>()
                : JsonSerializer.Deserialize<List<T>>(json, SerializerOptions) ?? new List<T>();
        }
        catch
        {
            return new List<T>();
        }
    }

    private static T? DeserializeObject<T>(string? json) where T : class
    {
        try
        {
            return string.IsNullOrWhiteSpace(json) ? null : JsonSerializer.Deserialize<T>(json, SerializerOptions);
        }
        catch
        {
            return null;
        }
    }

    private static List<string> CleanList(IEnumerable<string>? values)
    {
        return (values ?? Array.Empty<string>())
            .Select(value => value?.Trim() ?? string.Empty)
            .Where(value => !string.IsNullOrWhiteSpace(value))
            .Distinct(StringComparer.OrdinalIgnoreCase)
            .ToList();
    }

    private static string? TrimOrNull(string? value) => string.IsNullOrWhiteSpace(value) ? null : value.Trim();

    private static string? FormatDateRange(string? start, string? end, bool isCurrent)
    {
        if (string.IsNullOrWhiteSpace(start) && string.IsNullOrWhiteSpace(end)) return null;
        if (string.IsNullOrWhiteSpace(start)) return end;
        return $"{start} - {(isCurrent ? "Present" : end ?? "Present")}";
    }

    private static void AddBlock(List<string> lines, string title, IEnumerable<string> body)
    {
        var content = string.Join("\n", body.Where(line => !string.IsNullOrWhiteSpace(line)).Select(line => line.Trim())).Trim();
        if (string.IsNullOrWhiteSpace(content)) return;
        lines.Add($"{title}\n{content}");
    }

    private static void AddLine(List<string> lines, string? value)
    {
        if (!string.IsNullOrWhiteSpace(value)) lines.Add(value.Trim());
    }
}
