using Microsoft.AspNetCore.Mvc;
using RR3CommunityServer.Services;

namespace RR3CommunityServer.Controllers;

[ApiController]
[Route("api/[controller]")]
public class AssetManagementController : ControllerBase
{
    private readonly AssetExtractionService _assetExtraction;
    private readonly ILogger<AssetManagementController> _logger;
    private readonly string _assetBasePath;

    public AssetManagementController(
        AssetExtractionService assetExtraction,
        ILogger<AssetManagementController> logger,
        IConfiguration configuration)
    {
        _assetExtraction = assetExtraction;
        _logger = logger;
        _assetBasePath = configuration["AssetBasePath"] ?? Path.Combine(Directory.GetCurrentDirectory(), "Assets");
    }

    /// <summary>
    /// Extract a single .z asset file
    /// </summary>
    [HttpPost("extract")]
    public async Task<IActionResult> ExtractAsset([FromBody] ExtractRequest request)
    {
        try
        {
            var filePath = Path.Combine(_assetBasePath, request.FileName);
            var outputPath = await _assetExtraction.ExtractZFileAsync(filePath, request.OutputPath);

            return Ok(new
            {
                resultCode = 0,
                message = "Success",
                data = new
                {
                    inputFile = filePath,
                    outputFile = outputPath,
                    size = new FileInfo(outputPath).Length
                }
            });
        }
        catch (FileNotFoundException ex)
        {
            return NotFound(new { resultCode = 404, message = ex.Message });
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error extracting asset");
            return StatusCode(500, new { resultCode = 500, message = ex.Message });
        }
    }

    /// <summary>
    /// Pack a file to .z format
    /// </summary>
    [HttpPost("pack")]
    public async Task<IActionResult> PackAsset([FromBody] PackRequest request)
    {
        try
        {
            var filePath = Path.Combine(_assetBasePath, request.FileName);
            var outputPath = await _assetExtraction.PackZFileAsync(filePath, request.OutputPath);

            return Ok(new
            {
                resultCode = 0,
                message = "Success",
                data = new
                {
                    inputFile = filePath,
                    outputFile = outputPath,
                    size = new FileInfo(outputPath).Length
                }
            });
        }
        catch (FileNotFoundException ex)
        {
            return NotFound(new { resultCode = 404, message = ex.Message });
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error packing asset");
            return StatusCode(500, new { resultCode = 500, message = ex.Message });
        }
    }

    /// <summary>
    /// Batch extract all .z files in a directory
    /// </summary>
    [HttpPost("batch-extract")]
    public async Task<IActionResult> BatchExtract([FromBody] BatchExtractRequest request)
    {
        try
        {
            var inputDir = Path.Combine(_assetBasePath, request.InputDirectory);
            var outputDir = string.IsNullOrEmpty(request.OutputDirectory)
                ? null
                : Path.Combine(_assetBasePath, request.OutputDirectory);

            var results = await _assetExtraction.BatchExtractAsync(inputDir, outputDir);

            var successful = results.Count(r => !r.Value.StartsWith("ERROR:"));
            var failed = results.Count - successful;

            return Ok(new
            {
                resultCode = 0,
                message = "Success",
                data = new
                {
                    totalFiles = results.Count,
                    successful,
                    failed,
                    results = results.Select(r => new
                    {
                        inputFile = Path.GetFileName(r.Key),
                        outputFile = Path.GetFileName(r.Value),
                        status = r.Value.StartsWith("ERROR:") ? "failed" : "success",
                        error = r.Value.StartsWith("ERROR:") ? r.Value : null
                    })
                }
            });
        }
        catch (DirectoryNotFoundException ex)
        {
            return NotFound(new { resultCode = 404, message = ex.Message });
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error in batch extraction");
            return StatusCode(500, new { resultCode = 500, message = ex.Message });
        }
    }

    /// <summary>
    /// List all available .z assets
    /// </summary>
    [HttpGet("list")]
    public IActionResult ListAssets([FromQuery] string? directory = null)
    {
        try
        {
            var searchDir = string.IsNullOrEmpty(directory)
                ? _assetBasePath
                : Path.Combine(_assetBasePath, directory);

            if (!Directory.Exists(searchDir))
            {
                return NotFound(new { resultCode = 404, message = "Directory not found" });
            }

            var zFiles = Directory.GetFiles(searchDir, "*.z", SearchOption.AllDirectories)
                .Select(f => new
                {
                    fileName = Path.GetFileName(f),
                    relativePath = Path.GetRelativePath(_assetBasePath, f),
                    size = new FileInfo(f).Length,
                    modified = new FileInfo(f).LastWriteTimeUtc
                })
                .ToList();

            return Ok(new
            {
                resultCode = 0,
                message = "Success",
                data = new
                {
                    directory = searchDir,
                    fileCount = zFiles.Count,
                    files = zFiles
                }
            });
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error listing assets");
            return StatusCode(500, new { resultCode = 500, message = ex.Message });
        }
    }
}

public record ExtractRequest(string FileName, string? OutputPath = null);
public record PackRequest(string FileName, string? OutputPath = null);
public record BatchExtractRequest(string InputDirectory, string? OutputDirectory = null);
