using CraftingApi.Models;
using CraftingApi.Services;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using System.Security.Claims;

namespace CraftingApi.Controllers;

[ApiController]
[Route("api/[controller]")]
public class CraftingController : ControllerBase
{
    private readonly CraftingStore _crafting;

    public CraftingController(CraftingStore crafting)
    {
        _crafting = crafting;
    }

    [HttpGet("recipes")]
    [Authorize(Roles = "USER,SUPER")]
    public async Task<IActionResult> ListRecipes()
    {
        var recipes = await _crafting.ListRecipesAsync();
        return Ok(recipes.Select(CraftingRecipeResponse.FromModel).ToList());
    }

    [HttpGet("recipes/{recipeKey}")]
    [Authorize(Roles = "USER,SUPER")]
    public async Task<IActionResult> GetRecipe(string recipeKey)
    {
        var recipe = await _crafting.GetRecipeAsync(recipeKey);
        return recipe is null ? NotFound() : Ok(CraftingRecipeResponse.FromModel(recipe));
    }

    [HttpPost("recipes/{recipeKey}")]
    [Authorize(Roles = "SUPER")]
    public async Task<IActionResult> CreateRecipe(string recipeKey, [FromBody] UpsertCraftingRecipeRequest request)
    {
        var validationError = ValidateRecipeRequest(recipeKey, request);
        if (validationError is not null)
            return validationError;

        var recipe = _crafting.BuildRecipe(recipeKey, request);
        var created = await _crafting.CreateRecipeAsync(recipe);
        return created ? Ok(CraftingRecipeResponse.FromModel(recipe)) : Conflict("Recipe already exists");
    }

    [HttpPut("recipes/{recipeKey}")]
    [Authorize(Roles = "SUPER")]
    public async Task<IActionResult> UpsertRecipe(string recipeKey, [FromBody] UpsertCraftingRecipeRequest request)
    {
        var validationError = ValidateRecipeRequest(recipeKey, request);
        if (validationError is not null)
            return validationError;

        var recipe = await _crafting.UpsertRecipeAsync(recipeKey, request);
        return Ok(CraftingRecipeResponse.FromModel(recipe));
    }

    [HttpGet("characters/{characterId}/available-recipes")]
    [Authorize(Roles = "USER,SUPER")]
    public async Task<IActionResult> AvailableRecipes(string characterId)
    {
        var access = await ResolveCharacterAccessAsync(characterId);
        if (access is IActionResult errorResult)
            return errorResult;

        var available = await _crafting.GetAvailableRecipesAsync((CraftingStore.CharacterAccessResult)access!);
        return Ok(available);
    }

    [HttpPost("characters/{characterId}/craft")]
    [Authorize(Roles = "USER,SUPER")]
    public async Task<IActionResult> Craft(string characterId, [FromBody] CraftRecipeRequest request)
    {
        if (string.IsNullOrWhiteSpace(request.RecipeKey))
            return BadRequest("recipeKey required");
        if (request.Quantity <= 0)
            return BadRequest("quantity must be greater than 0");

        var access = await ResolveCharacterAccessAsync(characterId);
        if (access is IActionResult errorResult)
            return errorResult;

        var result = await _crafting.CraftAsync((CraftingStore.CharacterAccessResult)access!, request);
        return result.Status switch
        {
            CraftingStore.CraftStatus.RecipeNotFound => NotFound("Recipe not found"),
            CraftingStore.CraftStatus.MissingStation => Conflict("Required crafting station is not available"),
            CraftingStore.CraftStatus.MissingInputs => Conflict(new { missingRequirements = result.MissingRequirements }),
            CraftingStore.CraftStatus.InvalidRecipe => BadRequest(new { missingRequirements = result.MissingRequirements }),
            _ => Ok(new CraftRecipeResponse
            {
                CharacterId = characterId,
                RecipeKey = request.RecipeKey.Trim().ToLowerInvariant(),
                CraftedQuantity = result.CraftedQuantity,
                Consumed = result.Consumed,
                Produced = result.Produced
            })
        };
    }

    private async Task<object> ResolveCharacterAccessAsync(string characterId)
    {
        var userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
        if (string.IsNullOrWhiteSpace(userId))
            return Unauthorized();

        var access = await _crafting.ResolveCharacterAsync(characterId, userId, User.IsInRole("SUPER"));
        if (!access.Exists)
            return NotFound();
        if (!access.IsAuthorized)
            return Forbid();

        return access;
    }

    private IActionResult? ValidateRecipeRequest(string recipeKey, UpsertCraftingRecipeRequest request)
    {
        if (string.IsNullOrWhiteSpace(recipeKey))
            return BadRequest("recipeKey required");
        if (string.IsNullOrWhiteSpace(request.Name))
            return BadRequest("name required");
        if (request.Inputs.Count == 0)
            return BadRequest("At least one input is required");
        if (request.Outputs.Count == 0)
            return BadRequest("At least one output is required");
        if (request.Inputs.Any(i => string.IsNullOrWhiteSpace(i.ItemKey) || i.Quantity <= 0))
            return BadRequest("All inputs must have itemKey and quantity > 0");
        if (request.Outputs.Any(i => string.IsNullOrWhiteSpace(i.ItemKey) || i.Quantity <= 0))
            return BadRequest("All outputs must have itemKey and quantity > 0");
        return null;
    }
}
