using Microsoft.Playwright;
using Xunit;
using FluentAssertions;
using LittleShop.Tests.Infrastructure;

namespace LittleShop.Tests.UI;

[Collection("Playwright")]
public class AdminPanelTests : IClassFixture<TestWebApplicationFactory>, IAsyncLifetime
{
    private readonly TestWebApplicationFactory _factory;
    private IPlaywright? _playwright;
    private IBrowser? _browser;
    private IBrowserContext? _context;
    private IPage? _page;
    private readonly string _baseUrl;

    public AdminPanelTests(TestWebApplicationFactory factory)
    {
        _factory = factory;
        _baseUrl = "https://localhost:5001"; // Adjust based on your test configuration
    }

    public async Task InitializeAsync()
    {
        _playwright = await Playwright.CreateAsync();
        _browser = await _playwright.Chromium.LaunchAsync(new BrowserTypeLaunchOptions
        {
            Headless = true // Set to false for debugging
        });
        _context = await _browser.NewContextAsync(new BrowserNewContextOptions
        {
            IgnoreHTTPSErrors = true // For self-signed certificates in test
        });
        _page = await _context.NewPageAsync();
    }

    public async Task DisposeAsync()
    {
        if (_page != null) await _page.CloseAsync();
        if (_context != null) await _context.CloseAsync();
        if (_browser != null) await _browser.CloseAsync();
        _playwright?.Dispose();
    }

    [Fact]
    public async Task LoginPage_ShouldLoadWithoutErrors()
    {
        // Arrange & Act
        var response = await _page!.GotoAsync($"{_baseUrl}/Admin/Account/Login");

        // Assert
        response.Should().NotBeNull();
        response!.Status.Should().Be(200);
        
        // Check for login form elements
        var usernameInput = await _page.QuerySelectorAsync("input[name='Username']");
        var passwordInput = await _page.QuerySelectorAsync("input[name='Password']");
        var submitButton = await _page.QuerySelectorAsync("button[type='submit']");
        
        usernameInput.Should().NotBeNull();
        passwordInput.Should().NotBeNull();
        submitButton.Should().NotBeNull();
    }

    [Fact]
    public async Task Login_WithValidCredentials_ShouldRedirectToDashboard()
    {
        // Arrange
        await _page!.GotoAsync($"{_baseUrl}/Admin/Account/Login");

        // Act
        await _page.FillAsync("input[name='Username']", "admin");
        await _page.FillAsync("input[name='Password']", "admin");
        await _page.ClickAsync("button[type='submit']");
        
        // Wait for navigation
        await _page.WaitForURLAsync($"{_baseUrl}/Admin/Dashboard");

        // Assert
        _page.Url.Should().Contain("/Admin/Dashboard");
        
        // Check dashboard loaded
        var dashboardTitle = await _page.TextContentAsync("h1");
        dashboardTitle.Should().Contain("Dashboard");
    }

    [Fact]
    public async Task Login_WithInvalidCredentials_ShouldShowError()
    {
        // Arrange
        await _page!.GotoAsync($"{_baseUrl}/Admin/Account/Login");

        // Act
        await _page.FillAsync("input[name='Username']", "wronguser");
        await _page.FillAsync("input[name='Password']", "wrongpass");
        await _page.ClickAsync("button[type='submit']");

        // Assert
        // Should stay on login page
        _page.Url.Should().Contain("/Admin/Account/Login");
        
        // Check for error message
        var errorMessage = await _page.QuerySelectorAsync(".text-danger, .alert-danger");
        errorMessage.Should().NotBeNull();
    }

    [Fact]
    public async Task AdminPages_WithoutLogin_ShouldRedirectToLogin()
    {
        // Arrange & Act
        var pagesToTest = new[]
        {
            "/Admin/Dashboard",
            "/Admin/Categories",
            "/Admin/Products",
            "/Admin/Orders",
            "/Admin/Users"
        };

        foreach (var pageUrl in pagesToTest)
        {
            await _page!.GotoAsync($"{_baseUrl}{pageUrl}");
            
            // Assert - Should redirect to login
            _page.Url.Should().Contain("/Admin/Account/Login");
        }
    }

    [Fact]
    public async Task Dashboard_AfterLogin_ShouldLoadAllSections()
    {
        // Arrange - Login first
        await LoginAsAdmin();

        // Act
        await _page!.GotoAsync($"{_baseUrl}/Admin/Dashboard");

        // Assert
        var response = await _page.GotoAsync($"{_baseUrl}/Admin/Dashboard");
        response!.Status.Should().Be(200);

        // Check for dashboard sections
        var statsCards = await _page.QuerySelectorAllAsync(".card");
        statsCards.Count.Should().BeGreaterThan(0);

        // Check navigation menu is present
        var navMenu = await _page.QuerySelectorAsync(".navbar");
        navMenu.Should().NotBeNull();
    }

    [Fact]
    public async Task Categories_CRUD_ShouldWorkWithoutErrors()
    {
        // Arrange - Login first
        await LoginAsAdmin();

        // Navigate to Categories
        await _page!.GotoAsync($"{_baseUrl}/Admin/Categories");
        var response = await _page.GotoAsync($"{_baseUrl}/Admin/Categories");
        response!.Status.Should().Be(200);

        // Create Category
        await _page.ClickAsync("a[href*='Categories/Create']");
        await _page.WaitForURLAsync("**/Admin/Categories/Create");
        
        await _page.FillAsync("input[name='Name']", "Test Category");
        await _page.FillAsync("textarea[name='Description']", "Test Description");
        await _page.ClickAsync("button[type='submit']");

        // Should redirect back to index
        await _page.WaitForURLAsync("**/Admin/Categories");

        // Verify category appears in list
        var categoryName = await _page.TextContentAsync("td:has-text('Test Category')");
        categoryName.Should().NotBeNull();
    }

    [Fact]
    public async Task Products_Index_ShouldLoadWithoutErrors()
    {
        // Arrange - Login first
        await LoginAsAdmin();

        // Act
        var response = await _page!.GotoAsync($"{_baseUrl}/Admin/Products");

        // Assert
        response!.Status.Should().Be(200);
        
        // Check for products table or empty message
        var productsTable = await _page.QuerySelectorAsync("table");
        var emptyMessage = await _page.QuerySelectorAsync("text=No products found");
        
        (productsTable != null || emptyMessage != null).Should().BeTrue();
    }

    [Fact]
    public async Task Orders_Index_ShouldLoadWithoutErrors()
    {
        // Arrange - Login first
        await LoginAsAdmin();

        // Act
        var response = await _page!.GotoAsync($"{_baseUrl}/Admin/Orders");

        // Assert
        response!.Status.Should().Be(200);
        
        // Check for orders table or empty message
        var ordersTable = await _page.QuerySelectorAsync("table");
        var emptyMessage = await _page.QuerySelectorAsync("text=No orders found");
        
        (ordersTable != null || emptyMessage != null).Should().BeTrue();
    }

    [Fact]
    public async Task Users_Index_ShouldLoadWithoutErrors()
    {
        // Arrange - Login first
        await LoginAsAdmin();

        // Act
        var response = await _page!.GotoAsync($"{_baseUrl}/Admin/Users");

        // Assert
        response!.Status.Should().Be(200);
        
        // Should at least show the admin user
        var usersTable = await _page.QuerySelectorAsync("table");
        usersTable.Should().NotBeNull();
        
        var adminUser = await _page.TextContentAsync("td:has-text('admin')");
        adminUser.Should().NotBeNull();
    }

    [Fact]
    public async Task Logout_ShouldRedirectToLogin()
    {
        // Arrange - Login first
        await LoginAsAdmin();

        // Act - Find and click logout
        await _page!.ClickAsync("a[href*='Account/Logout']");

        // Assert
        await _page.WaitForURLAsync("**/Admin/Account/Login");
        _page.Url.Should().Contain("/Admin/Account/Login");
    }

    [Fact]
    public async Task NetworkErrors_ShouldBeCaptured()
    {
        // Arrange
        var failedRequests = new List<string>();
        _page!.RequestFailed += (_, request) =>
        {
            failedRequests.Add($"{request.Method} {request.Url} - {request.Failure}");
        };

        await LoginAsAdmin();

        // Act - Navigate through admin pages
        var pagesToCheck = new[]
        {
            "/Admin/Dashboard",
            "/Admin/Categories",
            "/Admin/Products",
            "/Admin/Orders",
            "/Admin/Users"
        };

        foreach (var pageUrl in pagesToCheck)
        {
            await _page.GotoAsync($"{_baseUrl}{pageUrl}");
        }

        // Assert - No failed requests
        failedRequests.Should().BeEmpty("No network requests should fail");
    }

    [Fact]
    public async Task ConsoleErrors_ShouldBeCaptured()
    {
        // Arrange
        var consoleErrors = new List<string>();
        _page!.Console += (_, msg) =>
        {
            if (msg.Type == "error")
            {
                consoleErrors.Add(msg.Text);
            }
        };

        await LoginAsAdmin();

        // Act - Navigate through admin pages
        var pagesToCheck = new[]
        {
            "/Admin/Dashboard",
            "/Admin/Categories",
            "/Admin/Products"
        };

        foreach (var pageUrl in pagesToCheck)
        {
            await _page.GotoAsync($"{_baseUrl}{pageUrl}");
        }

        // Assert - No console errors
        consoleErrors.Should().BeEmpty("No JavaScript errors should occur");
    }

    private async Task LoginAsAdmin()
    {
        await _page!.GotoAsync($"{_baseUrl}/Admin/Account/Login");
        await _page.FillAsync("input[name='Username']", "admin");
        await _page.FillAsync("input[name='Password']", "admin");
        await _page.ClickAsync("button[type='submit']");
        await _page.WaitForURLAsync($"{_baseUrl}/Admin/Dashboard");
    }
}