using Microsoft.Playwright;

namespace Books.E2E.Tests.Pages.Modals;

/// <summary>
/// Page object for the Add Order Line modal.
/// </summary>
public class AddOrderLineModalPage : BasePage
{
    private readonly ILocator _modal;
    private readonly ILocator _descriptionInput;
    private readonly ILocator _quantityInput;
    private readonly ILocator _unitInput;
    private readonly ILocator _unitPriceInput;
    private readonly ILocator _discountPercentInput;
    private readonly ILocator _vatCodeSelect;
    private readonly ILocator _submitButton;
    private readonly ILocator _cancelButton;

    public AddOrderLineModalPage(IPage page) : base(page)
    {
        _modal = page.Locator(".ant-modal:has-text('Tilfoej linje')");
        _descriptionInput = _modal.Locator("input").First; // Description is first input
        _quantityInput = _modal.Locator(".ant-form-item:has-text('Antal') input");
        _unitInput = _modal.Locator(".ant-form-item:has-text('Enhed') input");
        _unitPriceInput = _modal.Locator(".ant-form-item:has-text('Enhedspris') input");
        _discountPercentInput = _modal.Locator(".ant-form-item:has-text('Rabat') input");
        _vatCodeSelect = _modal.Locator(".ant-form-item:has-text('Momskode') .ant-select");
        _submitButton = _modal.GetByRole(AriaRole.Button, new() { Name = "Tilfoej" });
        _cancelButton = _modal.GetByRole(AriaRole.Button, new() { Name = "Annuller" });
    }

    /// <summary>
    /// Waits for the modal to be visible.
    /// </summary>
    public async Task WaitForModalToOpen()
    {
        await _modal.WaitForAsync(new() { State = WaitForSelectorState.Visible, Timeout = 5000 });
    }

    /// <summary>
    /// Enters the line description.
    /// </summary>
    public async Task EnterDescription(string description)
    {
        await _descriptionInput.ClearAsync();
        await _descriptionInput.FillAsync(description);
    }

    /// <summary>
    /// Enters the quantity.
    /// </summary>
    public async Task EnterQuantity(int quantity)
    {
        await _quantityInput.ClearAsync();
        await _quantityInput.FillAsync(quantity.ToString());
    }

    /// <summary>
    /// Enters the unit (e.g., "stk", "timer").
    /// </summary>
    public async Task EnterUnit(string unit)
    {
        await _unitInput.ClearAsync();
        await _unitInput.FillAsync(unit);
    }

    /// <summary>
    /// Enters the unit price.
    /// </summary>
    public async Task EnterUnitPrice(decimal price)
    {
        await _unitPriceInput.ClearAsync();
        await _unitPriceInput.FillAsync(price.ToString("F2"));
    }

    /// <summary>
    /// Enters a discount percentage.
    /// </summary>
    public async Task EnterDiscount(decimal discountPercent)
    {
        await _discountPercentInput.ClearAsync();
        await _discountPercentInput.FillAsync(discountPercent.ToString("F0"));
    }

    /// <summary>
    /// Selects a VAT code (e.g., "S25", "S0").
    /// </summary>
    public async Task SelectVatCode(string vatCode)
    {
        await _vatCodeSelect.ClickAsync();
        var dropdown = Page.Locator(".ant-select-dropdown:visible");
        await dropdown.WaitForAsync(new() { Timeout = 5000 });

        var option = dropdown.Locator($".ant-select-item-option:has-text('{vatCode}')");
        await option.ClickAsync();
    }

    /// <summary>
    /// Fills all required fields for a basic order line.
    /// </summary>
    public async Task FillBasicLine(string description, int quantity, decimal unitPrice)
    {
        await EnterDescription(description);
        await EnterQuantity(quantity);
        await EnterUnitPrice(unitPrice);
    }

    /// <summary>
    /// Fills all fields for a complete order line.
    /// </summary>
    public async Task FillCompleteLine(
        string description,
        int quantity,
        string unit,
        decimal unitPrice,
        decimal? discountPercent = null,
        string vatCode = "S25")
    {
        await EnterDescription(description);
        await EnterQuantity(quantity);
        await EnterUnit(unit);
        await EnterUnitPrice(unitPrice);

        if (discountPercent.HasValue)
        {
            await EnterDiscount(discountPercent.Value);
        }

        await SelectVatCode(vatCode);
    }

    /// <summary>
    /// Submits the form to add the line.
    /// </summary>
    public async Task Submit()
    {
        await _submitButton.ClickAsync();
        // Wait for modal to close or show error
        await Task.WhenAny(
            _modal.WaitForAsync(new() { State = WaitForSelectorState.Hidden, Timeout = 10000 }),
            Page.Locator(".ant-form-item-explain-error").WaitForAsync(new() { Timeout = 10000 })
        );
    }

    /// <summary>
    /// Cancels and closes the modal.
    /// </summary>
    public async Task Cancel()
    {
        await _cancelButton.ClickAsync();
        await _modal.WaitForAsync(new() { State = WaitForSelectorState.Hidden, Timeout = 5000 });
    }

    /// <summary>
    /// Checks if there are validation errors.
    /// </summary>
    public async Task<bool> HasValidationErrors()
    {
        return await _modal.Locator(".ant-form-item-explain-error").IsVisibleAsync();
    }

    /// <summary>
    /// Gets all validation error messages.
    /// </summary>
    public async Task<IReadOnlyList<string>> GetValidationErrors()
    {
        return await _modal.Locator(".ant-form-item-explain-error").AllTextContentsAsync();
    }

    /// <summary>
    /// Checks if the modal is visible.
    /// </summary>
    public async Task<bool> IsVisible()
    {
        return await _modal.IsVisibleAsync();
    }
}
