using System.Security.Claims;
using CalledIt.Domain.Dtos;
using CalledIt.Domain.Services;
using FluentValidation;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;

namespace CalledIt.Api.Controllers;

[ApiController]
[Authorize]
[Route("api/[controller]")]
public class BetController : ControllerBase
{
    private readonly IBetService _betService;
    private readonly IValidator<UpsertBetDto> _upsertBetValidator;

    public BetController(IBetService betService, IValidator<UpsertBetDto> upsertBetValidator)
    {
        _betService = betService;
        _upsertBetValidator = upsertBetValidator;
    }

    [HttpPut("{matchId}")]
    [ProducesResponseType(typeof(BetResponseDto), StatusCodes.Status200OK)]
    [ProducesResponseType(typeof(ValidationProblemDetails), StatusCodes.Status400BadRequest)]
    [ProducesResponseType(StatusCodes.Status404NotFound)]
    [ProducesResponseType(StatusCodes.Status409Conflict)]
    public async Task<ActionResult<BetResponseDto>> Upsert(int matchId, UpsertBetDto dto)
    {
        var validationResult = await _upsertBetValidator.ValidateAsync(dto);
        if (!validationResult.IsValid)
        {
            foreach (var error in validationResult.Errors)
            {
                ModelState.AddModelError(error.PropertyName, error.ErrorMessage);
            }

            return ValidationProblem(ModelState);
        }

        var userId = GetCurrentUserId();

        try
        {
            var result = await _betService.UpsertAsync(userId, matchId, dto);
            return Ok(result);
        }
        catch (KeyNotFoundException exception)
        {
            return NotFound(new { message = exception.Message });
        }
        catch (InvalidOperationException exception)
        {
            return Conflict(new { message = exception.Message });
        }
    }

    [HttpGet("competitions")]
    [ProducesResponseType(typeof(IReadOnlyList<int>), StatusCodes.Status200OK)]
    public async Task<ActionResult<IReadOnlyList<int>>> GetCompetitionsWithBets()
    {
        var userId = GetCurrentUserId();
        var result = await _betService.GetCompetitionIdsWithBetsAsync(userId);
        return Ok(result);
    }

    [HttpGet("match/{matchId}/stats")]
    [ProducesResponseType(typeof(MatchBetStatsDto), StatusCodes.Status200OK)]
    public async Task<ActionResult<MatchBetStatsDto>> GetMatchStats(int matchId)
    {
        var result = await _betService.GetMatchStatsAsync(matchId);
        return Ok(result);
    }

    [HttpGet]
    [ProducesResponseType(typeof(IReadOnlyList<BetResponseDto>), StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status400BadRequest)]
    public async Task<ActionResult<IReadOnlyList<BetResponseDto>>> GetByCompetition([FromQuery] int competitionId)
    {
        if (competitionId <= 0)
        {
            return BadRequest(new { message = "competitionId query parameter is required." });
        }

        var userId = GetCurrentUserId();
        var result = await _betService.GetByCompetitionAndUserAsync(userId, competitionId);
        return Ok(result);
    }

    private int GetCurrentUserId()
    {
        var claim = User.FindFirstValue("sub");
        if (claim is null || !int.TryParse(claim, out var id))
        {
            throw new UnauthorizedAccessException("Authenticated user identity is missing or invalid.");
        }
        return id;
    }
}
