using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using RacePlannerApi.Data;
using RacePlannerApi.DTOs;
using RacePlannerApi.Models;

namespace RacePlannerApi.Controllers;

[ApiController]
[Route("api/[controller]")]
[Authorize]
public class EventsController : ControllerBase
{
    private readonly RacePlannerDbContext _context;

    public EventsController(RacePlannerDbContext context)
    {
        _context = context;
    }

    [HttpPost]
    [Authorize(Roles = "Organizer")]
    public async Task<ActionResult<EventDto>> CreateEvent(CreateEventRequest request)
    {
        var userId = GetCurrentUserId();
        if (userId == null)
        {
            return Unauthorized();
        }

        var eventEntity = new Event
        {
            Name = request.Name,
            Description = request.Description,
            EventDate = request.EventDate,
            Location = request.Location,
            Category = request.Category,
            Tags = request.Tags ?? new List<string>(),
            MaxParticipants = request.MaxParticipants,
            OrganizerId = userId.Value,
            Status = EventStatus.Draft
        };

        _context.Events.Add(eventEntity);
        await _context.SaveChangesAsync();

        // Load organizer for response
        await _context.Entry(eventEntity).Reference(e => e.Organizer).LoadAsync();

        return CreatedAtAction(
            nameof(GetEvent),
            new { id = eventEntity.Id },
            MapToEventDto(eventEntity));
    }

    [HttpGet]
    [AllowAnonymous]
    public async Task<ActionResult<IEnumerable<EventDto>>> GetEvents(
        [FromQuery] EventFilterRequest? filter = null)
    {
        var query = _context.Events
            .Include(e => e.Organizer)
            .Include(e => e.Registrations)
            .AsQueryable();

        // Apply filters
        if (filter?.Category != null)
        {
            query = query.Where(e => e.Category == filter.Category);
        }

        if (filter?.Tags != null && filter.Tags.Any())
        {
            query = query.Where(e => e.Tags.Any(t => filter.Tags.Contains(t)));
        }

        if (filter?.FromDate != null)
        {
            query = query.Where(e => e.EventDate >= filter.FromDate);
        }

        if (filter?.ToDate != null)
        {
            query = query.Where(e => e.EventDate <= filter.ToDate);
        }

        if (filter?.Status != null && Enum.TryParse<EventStatus>(filter.Status, out var status))
        {
            query = query.Where(e => e.Status == status);
        }

        if (filter?.OrganizerId != null)
        {
            query = query.Where(e => e.OrganizerId == filter.OrganizerId);
        }

        // Default to showing published events only for anonymous users
        if (!User.Identity?.IsAuthenticated ?? true)
        {
            query = query.Where(e => e.Status == EventStatus.Published);
        }

        var events = await query
            .OrderBy(e => e.EventDate)
            .ToListAsync();

        return Ok(events.Select(MapToEventDto));
    }

    [HttpGet("{id}")]
    [AllowAnonymous]
    public async Task<ActionResult<EventDto>> GetEvent(Guid id)
    {
        var eventEntity = await _context.Events
            .Include(e => e.Organizer)
            .Include(e => e.Registrations)
            .FirstOrDefaultAsync(e => e.Id == id);

        if (eventEntity == null)
        {
            return NotFound();
        }

        // Draft events only visible to organizers
        if (eventEntity.Status == EventStatus.Draft)
        {
            var userId = GetCurrentUserId();
            if (userId == null || eventEntity.OrganizerId != userId)
            {
                return NotFound();
            }
        }

        return Ok(MapToEventDto(eventEntity));
    }

    [HttpPut("{id}")]
    [Authorize(Roles = "Organizer")]
    public async Task<ActionResult<EventDto>> UpdateEvent(Guid id, UpdateEventRequest request)
    {
        var userId = GetCurrentUserId();
        if (userId == null)
        {
            return Unauthorized();
        }

        var eventEntity = await _context.Events
            .Include(e => e.Organizer)
            .FirstOrDefaultAsync(e => e.Id == id);

        if (eventEntity == null)
        {
            return NotFound();
        }

        // Only organizer can update their event
        if (eventEntity.OrganizerId != userId)
        {
            return Forbid();
        }

        // Update fields
        if (request.Name != null) eventEntity.Name = request.Name;
        if (request.Description != null) eventEntity.Description = request.Description;
        if (request.EventDate != null) eventEntity.EventDate = request.EventDate.Value;
        if (request.Location != null) eventEntity.Location = request.Location;
        if (request.Status != null) eventEntity.Status = request.Status.Value;
        if (request.Category != null) eventEntity.Category = request.Category;
        if (request.Tags != null) eventEntity.Tags = request.Tags;
        if (request.MaxParticipants != null) eventEntity.MaxParticipants = request.MaxParticipants;

        eventEntity.UpdatedAt = DateTime.UtcNow;

        await _context.SaveChangesAsync();

        return Ok(MapToEventDto(eventEntity));
    }

    [HttpDelete("{id}")]
    [Authorize(Roles = "Organizer")]
    public async Task<IActionResult> DeleteEvent(Guid id)
    {
        var userId = GetCurrentUserId();
        if (userId == null)
        {
            return Unauthorized();
        }

        var eventEntity = await _context.Events.FindAsync(id);

        if (eventEntity == null)
        {
            return NotFound();
        }

        if (eventEntity.OrganizerId != userId)
        {
            return Forbid();
        }

        _context.Events.Remove(eventEntity);
        await _context.SaveChangesAsync();

        return NoContent();
    }

    private Guid? GetCurrentUserId()
    {
        var userIdClaim = User.FindFirst(System.Security.Claims.ClaimTypes.NameIdentifier)?.Value;
        if (Guid.TryParse(userIdClaim, out var userId))
        {
            return userId;
        }
        return null;
    }

    private static EventDto MapToEventDto(Event eventEntity)
    {
        return new EventDto
        {
            Id = eventEntity.Id,
            Name = eventEntity.Name,
            Description = eventEntity.Description,
            EventDate = eventEntity.EventDate,
            Location = eventEntity.Location,
            Status = eventEntity.Status.ToString(),
            Category = eventEntity.Category,
            Tags = eventEntity.Tags,
            MaxParticipants = eventEntity.MaxParticipants,
            CurrentRegistrations = eventEntity.Registrations?.Count ?? 0,
            CreatedAt = eventEntity.CreatedAt,
            UpdatedAt = eventEntity.UpdatedAt,
            Organizer = new UserSummaryDto
            {
                Id = eventEntity.Organizer.Id,
                Name = eventEntity.Organizer.Name,
                Email = eventEntity.Organizer.Email
            }
        };
    }
}