using AquaCubeIT.Service.NetFloppy.Models;
using Fat16Lib;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ModelBinding.Binders;
using System;
using System.IO;
using System.Text;

namespace AquaCubeIT.Service.NetFloppy.Controllers;

[ApiController]
[Route("[controller]")]
public class OperationsController : ControllerBase
{    
    private readonly ILogger<OperationsController> _logger;
    private const int DISK_SIZE_MB = 5;
    private const int DISK_SECTOR_SIZE = 512;          // 512 bytes/sector
    private const int DISK_SECTOR_COUNT = DISK_SIZE_MB * 1024 * 1024 / DISK_SECTOR_SIZE;     // ~2 MB (4000 * 512)
    private const long DISK_BYTE_SIZE = DISK_SECTOR_COUNT * DISK_SECTOR_SIZE;

    public OperationsController(ILogger<OperationsController> logger)
    {
        _logger = logger;
    }

    private ErrorResponsePayload GetExceptionPayload(Exception exception)
    {
        return new ErrorResponsePayload() {  ErrorNo = 16, Message = exception.Message, Exception = exception };
    }

    [Authorize(Policy = "MustBeUser")]
    [HttpPost("LoadImage")]
    public async Task<LoadImageResponse> LoadImage(LoadImageRequest request)
    {
        try
        {
            // Check image exists


            // Check permissions of user



            // Get image data
            byte[] data = null;

            if (System.IO.File.Exists("c:\\temp\\test_image1.img"))
            {

                data = await System.IO.File.ReadAllBytesAsync("c:\\temp\\test_image1.img");
            }
            else
            {
                var img = new Fat16Image(new Fat16ImageOptions
                {
                    TotalSizeBytes = DISK_BYTE_SIZE,
                    VolumeLabel = "NetFloppy"
                });

                img.AddFile("README.TXT", Encoding.ASCII.GetBytes("Welcome to NetFloppy\r\n"));
                img.AddFile("FF.CFG", Encoding.ASCII.GetBytes("# FF.CFG - FlashFloppy configuration (served inside FAT by backend)\r\ninterface = ibmpc\r\nhost = acorn\r\nindex-suppression = no\r\n\r\n# Enable speaker / fake disk drive sounds\r\nsound = on\r\nsound-volume = 19\r\n\r\n# Disable display devices\r\ndisplay-type = none\r\n"));
                img.AddFile("TEST.ADF", System.IO.File.ReadAllBytes("TestDisk.adf"));

                data = img.GetImage();
                img.SaveToFile("c:\\temp\\test_image1.img");

            }

          
            return new LoadImageResponse() { Success = true, Payload = new LoadImageResponsePayload() { DiskImage = data } };
        }
        catch(Exception e)
        {
            return new LoadImageResponse() { Success = false, Error = GetExceptionPayload(e) };
        }
    }
    
    private bool InRange(int lba, int offset, int len)
    {        

        long start = lba * DISK_SECTOR_SIZE + offset;
        long end = start + len;
        return end <= DISK_BYTE_SIZE;
    }

    //[Authorize(Policy = "MustBeUser")]
    [HttpPost("LoadSector")]
    public async Task<IActionResult> LoadSector(LoadSectorRequest request)
    {
        try
        {
            // Check image exists


            // Check permissions of user



            // Get image data
            byte[] data = null;

            if (System.IO.File.Exists("c:\\temp\\test_image1.img"))
            {

                data = await System.IO.File.ReadAllBytesAsync("c:\\temp\\test_image1.img");
            }
            else
            {
                var img = new Fat16Image(new Fat16ImageOptions
                {
                    TotalSizeBytes = DISK_BYTE_SIZE, 
                    VolumeLabel = "NetFloppy"
                });

                img.AddFile("README.TXT", Encoding.ASCII.GetBytes("Welcome to NetFloppy\r\n"));
                img.AddFile("FF.CFG", Encoding.ASCII.GetBytes("# FF.CFG - FlashFloppy configuration (served inside FAT by backend)\r\ninterface = ibmpc\r\nhost = acorn\r\nindex-suppression = no\r\n\r\n# Enable speaker / fake disk drive sounds\r\nsound = on\r\nsound-volume = 19\r\n\r\n# Disable display devices\r\ndisplay-type = none\r\n"));
                img.AddFile("TEST.ADF", System.IO.File.ReadAllBytes("TestDisk.adf"));

                data = img.GetImage();
                //img.SaveToFile("c:\\temp\\test_image1.img");

            }

            if (!this.InRange(request.Payload.Lba, request.Payload.Offset, request.Payload.Length))
            {
                throw new Exception("Invalid Disk Location");                
            }

            var startPosition = (request.Payload.Lba * DISK_SECTOR_SIZE) + request.Payload.Offset;
            var sectorData = data.Skip(startPosition).Take(request.Payload.Length).ToArray();

            //Response.ContentType = "application/octet-stream";
            //Response.ContentLength = sectorData.Length;                 
            //await Response.Body.WriteAsync(sectorData,0 , sectorData.Length);

            return new LoadSectorResponse() { Success = true, Payload = new LoadSectorResponsePayload() { Data = sectorData, Length = sectorData.Length } };

            //return new EmptyResult();
        }
        catch (Exception e)
        {
            //return new LoadSectorResponse() { Success = false, Error = GetExceptionPayload(e) };
            return BadRequest(e.Message);
        }
    }

    [Authorize(Policy = "MustBeUser")]
    [HttpPost("SaveImage")]
    public async Task<SaveImageResponse> SaveImage(SaveImageRequest request)
    {
        try
        {
            // Check image exists


            // Check permissions of user



            // Get image data        
            var data = request.Payload.Data;

            // Save to file
            await System.IO.File.WriteAllBytesAsync("c:\\temp\\test_image1.img", data);

            return new SaveImageResponse() { Success = true, Payload = new SaveImageResponsePayload() { BytesSaved = data.Length } };
        }
        catch (Exception e)
        {
            return new SaveImageResponse() { Success = false, Error = GetExceptionPayload(e) };
        }
    }
}
