using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using SportsDivision.Application.DTOs;
using SportsDivision.Application.Interfaces;
using SportsDivision.Domain.Enums;

namespace SportsDivision.Web.Controllers;

[Authorize]
public class TrackEventController : Controller
{
    private readonly IHeatManagementService _heatManagementService;
    private readonly ITournamentService _tournamentService;
    private readonly IScoringService _scoringService;
    private readonly IRegistrationService _registrationService;

    public TrackEventController(
        IHeatManagementService heatManagementService,
        ITournamentService tournamentService,
        IScoringService scoringService,
        IRegistrationService registrationService)
    {
        _heatManagementService = heatManagementService;
        _tournamentService = tournamentService;
        _scoringService = scoringService;
        _registrationService = registrationService;
    }

    [HttpGet]
    public async Task<IActionResult> Index(int tournamentEventLevelId)
    {
        if (tournamentEventLevelId <= 0)
        {
            ViewBag.ScoringTargets = await _tournamentService.GetEventLevelsByCategoryAsync(EventCategory.Track);
            ViewBag.ScoringController = "TrackEvent";
            ViewBag.ScoringTitle = "Track Event Scoring";
            return View("SelectEventLevel");
        }
        var rounds = await _heatManagementService.GetRoundsAsync(tournamentEventLevelId);
        ViewBag.TournamentEventLevelId = tournamentEventLevelId;

        var tel = await _tournamentService.GetEventLevelByIdAsync(tournamentEventLevelId);
        if (tel != null)
        {
            ViewBag.EventName = tel.EventName;
            ViewBag.LevelName = tel.EventLevelName;
            ViewBag.TournamentName = tel.TournamentName;
            ViewBag.RegistrationCount = tel.RegistrationCount;
        }

        // Final standings (placement points are awarded from the final round).
        var registrations = await _registrationService.GetByTournamentEventLevelAsync(tournamentEventLevelId);
        ViewBag.Standings = registrations
            .Where(r => r.Score?.Placement != null)
            .OrderBy(r => r.Score!.Placement)
            .ToList();

        return View(rounds);
    }

    [HttpGet]
    public async Task<IActionResult> ManageRound(int roundId)
    {
        var round = await _heatManagementService.GetRoundWithHeatsAsync(roundId);
        if (round == null)
        {
            return NotFound();
        }

        ViewBag.TournamentEventLevelId = round.TournamentEventLevelId;
        var rounds = await _heatManagementService.GetRoundsAsync(round.TournamentEventLevelId);
        ViewBag.HasNextRound = rounds.Any(r => r.RoundOrder == round.RoundOrder + 1);

        return View(round);
    }

    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> CreateRound(RoundCreateDto dto)
    {
        if (!ModelState.IsValid)
        {
            return RedirectToAction(nameof(Index), new { tournamentEventLevelId = dto.TournamentEventLevelId });
        }

        await _heatManagementService.CreateRoundAsync(dto);
        return RedirectToAction(nameof(Index), new { tournamentEventLevelId = dto.TournamentEventLevelId });
    }

    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> SeedHeats(int roundId, SeedingMethod method, int lanesPerHeat = 8)
    {
        await _heatManagementService.SeedHeatsAsync(roundId, method, lanesPerHeat);
        return RedirectToAction(nameof(ManageRound), new { roundId });
    }

    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> SaveTimes(int heatId, int roundId, List<HeatLaneUpdateDto> lanes)
    {
        var recordedBy = User.Identity?.Name ?? "Unknown";
        await _heatManagementService.SaveHeatTimesAsync(heatId, lanes, recordedBy);
        TempData["SuccessMessage"] = "Heat times saved.";
        return RedirectToAction(nameof(ManageRound), new { roundId });
    }

    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> CalculateAdvancement(int roundId)
    {
        await _heatManagementService.CalculateAdvancementAsync(roundId);
        return RedirectToAction(nameof(ManageRound), new { roundId });
    }

    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> PopulateNextRound(int roundId)
    {
        var round = await _heatManagementService.GetRoundWithHeatsAsync(roundId);
        try
        {
            await _heatManagementService.PopulateNextRoundAsync(roundId);
            TempData["SuccessMessage"] = "Advancing athletes moved into the next round.";
        }
        catch (InvalidOperationException ex)
        {
            TempData["ErrorMessage"] = ex.Message;
        }
        return RedirectToAction(nameof(Index), new { tournamentEventLevelId = round?.TournamentEventLevelId });
    }

    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> CompleteHeat(int heatId)
    {
        await _heatManagementService.CompleteHeatAsync(heatId);
        return RedirectToAction(nameof(ManageRound), new { roundId = heatId });
    }

    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> CompleteRound(int roundId)
    {
        await _heatManagementService.CompleteRoundAsync(roundId);
        return RedirectToAction(nameof(ManageRound), new { roundId });
    }

    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> CalculateFinalStandings(int tournamentEventLevelId)
    {
        try
        {
            var recordedBy = User.Identity?.Name ?? "Unknown";
            await _scoringService.CalculateTrackFinalResultsAsync(tournamentEventLevelId, recordedBy);
            TempData["SuccessMessage"] = "Final standings calculated and placement points awarded.";
        }
        catch (KeyNotFoundException)
        {
            return NotFound();
        }
        catch (InvalidOperationException ex)
        {
            TempData["ErrorMessage"] = ex.Message;
        }

        return RedirectToAction(nameof(Index), new { tournamentEventLevelId });
    }
}
