using System.Net;
using System.Net.Http.Json;
using FluentAssertions;
using Microsoft.AspNetCore.Mvc.Testing;
using RacePlannerApi.DTOs;
using RacePlannerApi.Models;
using Xunit;

namespace backend.Tests.Integration;

public class EventsIntegrationTests : IntegrationTestBase
{
    public EventsIntegrationTests(CustomWebApplicationFactory factory) : base(factory) { }

    private async Task<string> GetOrganizerTokenAsync()
    {
        // Register and login as organizer
        var registerRequest = new RegisterRequest
        {
            Email = "organizer@test.com",
            Password = "SecurePass123!",
            Name = "Test Organizer",
            Role = UserRole.Organizer
        };
        await _client.PostAsJsonAsync("/api/auth/register", registerRequest);

        var loginRequest = new LoginRequest
        {
            Email = "organizer@test.com",
            Password = "SecurePass123!"
        };
        var loginResponse = await _client.PostAsJsonAsync("/api/auth/login", loginRequest);
        var authResult = await loginResponse.Content.ReadFromJsonAsync<AuthResponse>();
        return authResult!.Token;
    }

    [Fact]
    public async Task GetEvents_ReturnsPublishedEvents()
    {
        // Act
        var response = await _client.GetAsync("/api/events");

        // Assert
        response.StatusCode.Should().Be(HttpStatusCode.OK);
        var events = await response.Content.ReadFromJsonAsync<List<EventDto>>();
        events.Should().NotBeNull();
    }

    [Fact]
    public async Task CreateEvent_WithValidData_ReturnsCreated()
    {
        // Arrange
        var token = await GetOrganizerTokenAsync();
        var client = CreateAuthenticatedClient(token);

        var request = new CreateEventRequest
        {
            Name = "Test Marathon",
            Description = "A test marathon event",
            EventDate = DateTime.UtcNow.AddDays(30),
            Location = "Test City",
            Category = "Running",
            Tags = new List<string>(),
            MaxParticipants = 100
        };

        // Act
        var response = await client.PostAsJsonAsync("/api/events", request);

        // Assert
        response.StatusCode.Should().Be(HttpStatusCode.Created);
        var result = await response.Content.ReadFromJsonAsync<EventDto>();
        result.Should().NotBeNull();
        result!.Name.Should().Be(request.Name);
        result.Status.Should().Be("Draft");
    }

    [Fact]
    public async Task CreateEvent_WithoutAuth_ReturnsUnauthorized()
    {
        // Arrange
        var request = new CreateEventRequest
        {
            Name = "Test Event",
            EventDate = DateTime.UtcNow.AddDays(30),
            Location = "Test City"
        };

        // Act
        var response = await _client.PostAsJsonAsync("/api/events", request);

        // Assert
        response.StatusCode.Should().Be(HttpStatusCode.Unauthorized);
    }

    [Fact]
    public async Task GetEvent_WithValidId_ReturnsEvent()
    {
        // Arrange - Create an event first
        var token = await GetOrganizerTokenAsync();
        var client = CreateAuthenticatedClient(token);

        var createRequest = new CreateEventRequest
        {
            Name = "Test Event",
            Description = "Test description",
            EventDate = DateTime.UtcNow.AddDays(30),
            Location = "Test City",
            Category = "Running",
            Tags = new List<string>(),
            MaxParticipants = 50
        };
        var createResponse = await client.PostAsJsonAsync("/api/events", createRequest);
        var createdEvent = await createResponse.Content.ReadFromJsonAsync<EventDto>();

        // Publish the event so it's visible
        var updateRequest = new UpdateEventRequest
        {
            Status = EventStatus.Published
        };
        await client.PutAsJsonAsync($"/api/events/{createdEvent!.Id}", updateRequest);

        // Act - Get the event as anonymous user
        var getResponse = await _client.GetAsync($"/api/events/{createdEvent.Id}");

        // Assert
        getResponse.StatusCode.Should().Be(HttpStatusCode.OK);
        var result = await getResponse.Content.ReadFromJsonAsync<EventDto>();
        result.Should().NotBeNull();
        result!.Id.Should().Be(createdEvent.Id);
    }

    [Fact]
    public async Task GetEvent_WithInvalidId_ReturnsNotFound()
    {
        // Act
        var response = await _client.GetAsync($"/api/events/{Guid.NewGuid()}");

        // Assert
        response.StatusCode.Should().Be(HttpStatusCode.NotFound);
    }

    [Fact]
    public async Task UpdateEvent_WithValidData_ReturnsUpdatedEvent()
    {
        // Arrange
        var token = await GetOrganizerTokenAsync();
        var client = CreateAuthenticatedClient(token);

        var createRequest = new CreateEventRequest
        {
            Name = "Original Name",
            EventDate = DateTime.UtcNow.AddDays(30),
            Location = "Original Location",
            Category = "Running",
            Tags = new List<string>(),
            MaxParticipants = 50
        };
        var createResponse = await client.PostAsJsonAsync("/api/events", createRequest);
        var createdEvent = await createResponse.Content.ReadFromJsonAsync<EventDto>();

        var updateRequest = new UpdateEventRequest
        {
            Name = "Updated Name",
            Description = "Updated description"
        };

        // Act
        var response = await client.PutAsJsonAsync($"/api/events/{createdEvent!.Id}", updateRequest);

        // Assert
        response.StatusCode.Should().Be(HttpStatusCode.OK);
        var result = await response.Content.ReadFromJsonAsync<EventDto>();
        result.Should().NotBeNull();
        result!.Name.Should().Be("Updated Name");
        result.Description.Should().Be("Updated description");
    }

    [Fact]
    public async Task DeleteEvent_AsOrganizer_ReturnsNoContent()
    {
        // Arrange
        var token = await GetOrganizerTokenAsync();
        var client = CreateAuthenticatedClient(token);

        var createRequest = new CreateEventRequest
        {
            Name = "Event to Delete",
            EventDate = DateTime.UtcNow.AddDays(30),
            Location = "Test City",
            Category = "Running",
            Tags = new List<string>(),
            MaxParticipants = 50
        };
        var createResponse = await client.PostAsJsonAsync("/api/events", createRequest);
        var createdEvent = await createResponse.Content.ReadFromJsonAsync<EventDto>();

        // Act
        var response = await client.DeleteAsync($"/api/events/{createdEvent!.Id}");

        // Assert
        response.StatusCode.Should().Be(HttpStatusCode.NoContent);

        // Verify event is deleted
        var getResponse = await client.GetAsync($"/api/events/{createdEvent.Id}");
        getResponse.StatusCode.Should().Be(HttpStatusCode.NotFound);
    }
}
