using System;
using AvaloniaEdit.Document;
using MarkdownEditor.Constants;
using MarkdownEditor.Models;

namespace MarkdownEditor.Services;

/// <summary>
/// Default implementation of <see cref="IMarkdownFormattingService"/>.
/// Provides markdown formatting operations on text documents.
/// </summary>
public class MarkdownFormattingService : IMarkdownFormattingService
{
    /// <inheritdoc/>
    public TextSelection WrapSelection(TextDocument document, TextSelection selection, string before, string after)
    {
        if (document == null)
        {
            throw new ArgumentNullException(nameof(document));
        }
        if (selection == null)
        {
            throw new ArgumentNullException(nameof(selection));
        }

        // Normalize selection bounds
        selection.Normalize(document.TextLength);

        var selected = GetSelectedText(document, selection);
        var newText = before + (string.IsNullOrEmpty(selected) ? AppConstants.Markdown.DefaultPlaceholder : selected) + after;

        // Use Document API for thread-safe editing
        document.BeginUpdate();
        try
        {
            document.Remove(selection.Start, selection.Length);
            document.Insert(selection.Start, newText);
        }
        finally
        {
            document.EndUpdate();
        }

        // Calculate new selection to highlight the wrapped content
        var newStart = selection.Start + before.Length;
        var textLength = (string.IsNullOrEmpty(selected) ? AppConstants.Markdown.DefaultPlaceholder : selected).Length;
        
        return new TextSelection(newStart, newStart + textLength);
    }

    /// <inheritdoc/>
    public TextSelection AddLinePrefix(TextDocument document, TextSelection selection, string prefix)
    {
        if (document == null)
        {
            throw new ArgumentNullException(nameof(document));
        }
        if (selection == null)
        {
            throw new ArgumentNullException(nameof(selection));
        }
        if (string.IsNullOrEmpty(prefix))
        {
            throw new ArgumentException("Prefix cannot be null or empty.", nameof(prefix));
        }

        // Normalize selection bounds
        selection.Normalize(document.TextLength);

        // Find the start of the current line
        var text = document.Text;
        var lineStart = text.LastIndexOf('\n', Math.Max(0, selection.Start - 1)) + 1;

        // Use Document API for thread-safe editing
        document.BeginUpdate();
        try
        {
            document.Insert(lineStart, prefix);
        }
        finally
        {
            document.EndUpdate();
        }

        // Update selection position
        var newPos = lineStart + prefix.Length;
        return new TextSelection(newPos, newPos);
    }

    /// <inheritdoc/>
    public string GetSelectedText(TextDocument document, TextSelection selection)
    {
        if (document == null || selection == null)
        {
            return string.Empty;
        }

        var length = selection.Length;
        if (selection.Start >= 0 && 
            length > 0 && 
            selection.Start + length <= document.TextLength)
        {
            return document.GetText(selection.Start, length);
        }

        return string.Empty;
    }
}

