using Apollinare.API.Services.Reports;
using Apollinare.Domain.Entities;
using Apollinare.Infrastructure.Data;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;

namespace Apollinare.API.Controllers;

[ApiController]
[Route("api/report-resources")]
public class ReportResourcesController : ControllerBase
{
    private readonly AppollinareDbContext _context;

    public ReportResourcesController(AppollinareDbContext context)
    {
        _context = context;
    }

    #region Fonts

    [HttpGet("fonts")]
    public async Task<ActionResult<List<ReportFontDto>>> GetFonts()
    {
        var fonts = await _context.ReportFonts
            .Where(f => f.Attivo)
            .OrderBy(f => f.FontFamily)
            .ThenBy(f => f.FontStyle)
            .Select(f => new ReportFontDto
            {
                Id = f.Id,
                Nome = f.Nome,
                FontFamily = f.FontFamily,
                FontStyle = f.FontStyle,
                MimeType = f.MimeType,
                FileSize = f.FileSize,
                Attivo = f.Attivo
            })
            .ToListAsync();

        return fonts;
    }

    [HttpGet("fonts/{id}")]
    public async Task<ActionResult<ReportFontDto>> GetFont(int id)
    {
        var font = await _context.ReportFonts.FindAsync(id);
        if (font == null)
            return NotFound();

        return new ReportFontDto
        {
            Id = font.Id,
            Nome = font.Nome,
            FontFamily = font.FontFamily,
            FontStyle = font.FontStyle,
            FontDataBase64 = Convert.ToBase64String(font.FontData),
            MimeType = font.MimeType,
            FileSize = font.FileSize,
            Attivo = font.Attivo
        };
    }

    [HttpGet("fonts/{id}/download")]
    public async Task<IActionResult> DownloadFont(int id)
    {
        var font = await _context.ReportFonts.FindAsync(id);
        if (font == null)
            return NotFound();

        var extension = font.MimeType switch
        {
            "font/otf" => ".otf",
            "font/woff" => ".woff",
            "font/woff2" => ".woff2",
            _ => ".ttf"
        };

        return File(font.FontData, font.MimeType, $"{font.FontFamily}-{font.FontStyle}{extension}");
    }

    [HttpPost("fonts")]
    public async Task<ActionResult<ReportFontDto>> UploadFont([FromForm] string nome, [FromForm] string fontFamily, [FromForm] string fontStyle, IFormFile file)
    {
        if (file == null || file.Length == 0)
            return BadRequest("No file provided");

        var allowedMimeTypes = new[] { "font/ttf", "font/otf", "font/woff", "font/woff2", "application/x-font-ttf", "application/x-font-otf" };
        var mimeType = file.ContentType;

        // Normalize mime type
        if (file.FileName.EndsWith(".ttf", StringComparison.OrdinalIgnoreCase))
            mimeType = "font/ttf";
        else if (file.FileName.EndsWith(".otf", StringComparison.OrdinalIgnoreCase))
            mimeType = "font/otf";
        else if (file.FileName.EndsWith(".woff", StringComparison.OrdinalIgnoreCase))
            mimeType = "font/woff";
        else if (file.FileName.EndsWith(".woff2", StringComparison.OrdinalIgnoreCase))
            mimeType = "font/woff2";

        using var ms = new MemoryStream();
        await file.CopyToAsync(ms);
        var fontData = ms.ToArray();

        var font = new ReportFont
        {
            Nome = nome,
            FontFamily = fontFamily,
            FontStyle = fontStyle ?? "Regular",
            FontData = fontData,
            MimeType = mimeType,
            FileSize = fontData.Length,
            Attivo = true,
            CreatedAt = DateTime.UtcNow
        };

        _context.ReportFonts.Add(font);
        await _context.SaveChangesAsync();

        return new ReportFontDto
        {
            Id = font.Id,
            Nome = font.Nome,
            FontFamily = font.FontFamily,
            FontStyle = font.FontStyle,
            MimeType = font.MimeType,
            FileSize = font.FileSize,
            Attivo = font.Attivo
        };
    }

    [HttpDelete("fonts/{id}")]
    public async Task<IActionResult> DeleteFont(int id)
    {
        var font = await _context.ReportFonts.FindAsync(id);
        if (font == null)
            return NotFound();

        _context.ReportFonts.Remove(font);
        await _context.SaveChangesAsync();

        return NoContent();
    }

    [HttpGet("fonts/families")]
    public async Task<ActionResult<List<string>>> GetFontFamilies()
    {
        var families = await _context.ReportFonts
            .Where(f => f.Attivo)
            .Select(f => f.FontFamily)
            .Distinct()
            .OrderBy(f => f)
            .ToListAsync();

        // Add system fonts
        var systemFonts = new[] { "Helvetica", "Times New Roman", "Courier", "Arial" };
        return systemFonts.Concat(families).Distinct().OrderBy(f => f).ToList();
    }

    #endregion

    #region Images

    [HttpGet("images")]
    public async Task<ActionResult<List<ReportImageDto>>> GetImages([FromQuery] string? categoria = null)
    {
        var query = _context.ReportImages.Where(i => i.Attivo);

        if (!string.IsNullOrEmpty(categoria))
        {
            query = query.Where(i => i.Categoria == categoria);
        }

        var images = await query
            .OrderBy(i => i.Categoria)
            .ThenBy(i => i.Nome)
            .Select(i => new ReportImageDto
            {
                Id = i.Id,
                Nome = i.Nome,
                Categoria = i.Categoria,
                MimeType = i.MimeType,
                Width = i.Width,
                Height = i.Height,
                FileSize = i.FileSize,
                Attivo = i.Attivo,
                // Include small thumbnail for listing
                ImageDataBase64 = Convert.ToBase64String(i.ImageData)
            })
            .ToListAsync();

        return images;
    }

    [HttpGet("images/{id}")]
    public async Task<ActionResult<ReportImageDto>> GetImage(int id)
    {
        var image = await _context.ReportImages.FindAsync(id);
        if (image == null)
            return NotFound();

        return new ReportImageDto
        {
            Id = image.Id,
            Nome = image.Nome,
            Categoria = image.Categoria,
            ImageDataBase64 = Convert.ToBase64String(image.ImageData),
            MimeType = image.MimeType,
            Width = image.Width,
            Height = image.Height,
            FileSize = image.FileSize,
            Attivo = image.Attivo
        };
    }

    [HttpGet("images/{id}/download")]
    public async Task<IActionResult> DownloadImage(int id)
    {
        var image = await _context.ReportImages.FindAsync(id);
        if (image == null)
            return NotFound();

        var extension = image.MimeType switch
        {
            "image/jpeg" => ".jpg",
            "image/gif" => ".gif",
            "image/svg+xml" => ".svg",
            "image/webp" => ".webp",
            _ => ".png"
        };

        return File(image.ImageData, image.MimeType, $"{image.Nome}{extension}");
    }

    [HttpPost("images")]
    public async Task<ActionResult<ReportImageDto>> UploadImage([FromForm] string nome, [FromForm] string? categoria, IFormFile file)
    {
        if (file == null || file.Length == 0)
            return BadRequest("No file provided");

        var allowedMimeTypes = new[] { "image/png", "image/jpeg", "image/gif", "image/svg+xml", "image/webp" };
        if (!allowedMimeTypes.Contains(file.ContentType))
            return BadRequest($"Invalid file type. Allowed: {string.Join(", ", allowedMimeTypes)}");

        using var ms = new MemoryStream();
        await file.CopyToAsync(ms);
        var imageData = ms.ToArray();

        // Get image dimensions (basic for common formats)
        int width = 0, height = 0;
        try
        {
            // Use basic header parsing for common formats
            if (file.ContentType == "image/png" && imageData.Length > 24)
            {
                width = BitConverter.ToInt32(new[] { imageData[19], imageData[18], imageData[17], imageData[16] }, 0);
                height = BitConverter.ToInt32(new[] { imageData[23], imageData[22], imageData[21], imageData[20] }, 0);
            }
            else if (file.ContentType == "image/jpeg" && imageData.Length > 2)
            {
                // JPEG dimension parsing is complex, set defaults
                width = 100;
                height = 100;
            }
        }
        catch
        {
            // Ignore dimension parsing errors
        }

        var image = new ReportImage
        {
            Nome = nome,
            Categoria = categoria ?? "Generale",
            ImageData = imageData,
            MimeType = file.ContentType,
            Width = width,
            Height = height,
            FileSize = imageData.Length,
            Attivo = true,
            CreatedAt = DateTime.UtcNow
        };

        _context.ReportImages.Add(image);
        await _context.SaveChangesAsync();

        return new ReportImageDto
        {
            Id = image.Id,
            Nome = image.Nome,
            Categoria = image.Categoria,
            ImageDataBase64 = Convert.ToBase64String(image.ImageData),
            MimeType = image.MimeType,
            Width = image.Width,
            Height = image.Height,
            FileSize = image.FileSize,
            Attivo = image.Attivo
        };
    }

    [HttpPut("images/{id}")]
    public async Task<ActionResult<ReportImageDto>> UpdateImage(int id, [FromBody] ReportImageDto dto)
    {
        var image = await _context.ReportImages.FindAsync(id);
        if (image == null)
            return NotFound();

        image.Nome = dto.Nome;
        image.Categoria = dto.Categoria;
        image.UpdatedAt = DateTime.UtcNow;

        await _context.SaveChangesAsync();

        return new ReportImageDto
        {
            Id = image.Id,
            Nome = image.Nome,
            Categoria = image.Categoria,
            MimeType = image.MimeType,
            Width = image.Width,
            Height = image.Height,
            FileSize = image.FileSize,
            Attivo = image.Attivo
        };
    }

    [HttpDelete("images/{id}")]
    public async Task<IActionResult> DeleteImage(int id)
    {
        var image = await _context.ReportImages.FindAsync(id);
        if (image == null)
            return NotFound();

        _context.ReportImages.Remove(image);
        await _context.SaveChangesAsync();

        return NoContent();
    }

    [HttpGet("images/categories")]
    public async Task<ActionResult<List<string>>> GetImageCategories()
    {
        var categories = await _context.ReportImages
            .Where(i => i.Attivo)
            .Select(i => i.Categoria)
            .Distinct()
            .OrderBy(c => c)
            .ToListAsync();

        return categories;
    }

    #endregion
}
