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 AnnouncementsController : ControllerBase
{
    private readonly RacePlannerDbContext _context;

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

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

        // Verify event exists and user is organizer
        var eventEntity = await _context.Events
            .FirstOrDefaultAsync(e => e.Id == request.EventId);

        if (eventEntity == null)
        {
            return NotFound(new { error = "Event not found" });
        }

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

        var announcement = new Announcement
        {
            EventId = request.EventId,
            Title = request.Title,
            Content = request.Content,
            AuthorId = userId.Value,
            IsPublished = true
        };

        _context.Announcements.Add(announcement);
        await _context.SaveChangesAsync();

        // Load related data
        await _context.Entry(announcement)
            .Reference(a => a.Event)
            .LoadAsync();
        await _context.Entry(announcement)
            .Reference(a => a.Author)
            .LoadAsync();

        // TODO: Send notifications to registered participants (Task 7.7)

        return CreatedAtAction(
            nameof(GetAnnouncement),
            new { id = announcement.Id },
            MapToAnnouncementDto(announcement));
    }

    [HttpGet("{id}")]
    [AllowAnonymous]
    public async Task<ActionResult<AnnouncementDto>> GetAnnouncement(Guid id)
    {
        var announcement = await _context.Announcements
            .Include(a => a.Event)
            .Include(a => a.Author)
            .FirstOrDefaultAsync(a => a.Id == id);

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

        // Only show published announcements to participants
        if (!announcement.IsPublished)
        {
            var userId = GetCurrentUserId();
            if (userId == null || announcement.Event.OrganizerId != userId.Value)
            {
                return NotFound();
            }
        }

        return Ok(MapToAnnouncementDto(announcement));
    }

    [HttpGet("event/{eventId}")]
    [AllowAnonymous]
    public async Task<ActionResult<IEnumerable<AnnouncementDto>>> GetEventAnnouncements(Guid eventId)
    {
        var userId = GetCurrentUserId();
        var isOrganizer = false;

        if (userId != null)
        {
            isOrganizer = await _context.Events
                .AnyAsync(e => e.Id == eventId && e.OrganizerId == userId.Value);
        }

        var query = _context.Announcements
            .Include(a => a.Event)
            .Include(a => a.Author)
            .Where(a => a.EventId == eventId)
            .AsQueryable();

        // Only show published announcements to non-organizers
        if (!isOrganizer)
        {
            query = query.Where(a => a.IsPublished);
        }

        var announcements = await query
            .OrderByDescending(a => a.CreatedAt)
            .ToListAsync();

        return Ok(announcements.Select(MapToAnnouncementDto));
    }

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

        var announcement = await _context.Announcements
            .Include(a => a.Event)
            .Include(a => a.Author)
            .FirstOrDefaultAsync(a => a.Id == id);

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

        // Only organizer can update
        if (announcement.Event.OrganizerId != userId.Value)
        {
            return Forbid();
        }

        // Update fields
        if (request.Title != null) announcement.Title = request.Title;
        if (request.Content != null) announcement.Content = request.Content;
        if (request.IsPublished.HasValue) announcement.IsPublished = request.IsPublished.Value;

        announcement.UpdatedAt = DateTime.UtcNow;

        await _context.SaveChangesAsync();

        return Ok(MapToAnnouncementDto(announcement));
    }

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

        var announcement = await _context.Announcements
            .Include(a => a.Event)
            .FirstOrDefaultAsync(a => a.Id == id);

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

        // Only organizer can delete
        if (announcement.Event.OrganizerId != userId.Value)
        {
            return Forbid();
        }

        _context.Announcements.Remove(announcement);
        await _context.SaveChangesAsync();

        return NoContent();
    }

    [HttpGet("my-announcements")]
    public async Task<ActionResult<IEnumerable<AnnouncementDto>>> GetMyAnnouncements()
    {
        var userId = GetCurrentUserId();
        if (userId == null)
        {
            return Unauthorized();
        }

        // Get user registrations
        var userRegistrationEventIds = await _context.Registrations
            .Where(r => r.ParticipantId == userId.Value && r.Status != RegistrationStatus.Cancelled)
            .Select(r => r.EventId)
            .ToListAsync();

        // Get announcements for those events
        var announcements = await _context.Announcements
            .Include(a => a.Event)
            .Include(a => a.Author)
            .Where(a => userRegistrationEventIds.Contains(a.EventId) && a.IsPublished)
            .OrderByDescending(a => a.CreatedAt)
            .ToListAsync();

        return Ok(announcements.Select(MapToAnnouncementDto));
    }

    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 AnnouncementDto MapToAnnouncementDto(Announcement announcement)
    {
        return new AnnouncementDto
        {
            Id = announcement.Id,
            EventId = announcement.EventId,
            EventName = announcement.Event?.Name ?? string.Empty,
            Title = announcement.Title,
            Content = announcement.Content,
            AuthorId = announcement.AuthorId,
            AuthorName = announcement.Author?.Name ?? string.Empty,
            CreatedAt = announcement.CreatedAt,
            UpdatedAt = announcement.UpdatedAt,
            IsPublished = announcement.IsPublished
        };
    }
}