using System;
using System.IO;
using System.Net;
using Xilium.CefGlue;

namespace Robust.Client.WebView.Cef
{
    internal interface IRequestResult
    {
        CefResourceHandler MakeHandler();
    }

    internal sealed class RequestResultStream : IRequestResult
    {
        private readonly Stream _stream;
        private readonly HttpStatusCode _code;
        private readonly string _contentType;

        public RequestResultStream(Stream stream, string contentType, HttpStatusCode code)
        {
            _stream = stream;
            _code = code;
            _contentType = contentType;
        }

        public CefResourceHandler MakeHandler()
        {
            return new Handler(_stream, _contentType, _code);
        }

        private sealed class Handler : CefResourceHandler
        {
            // TODO: async
            // TODO: exception handling

            private readonly Stream _stream;
            private readonly HttpStatusCode _code;
            private readonly string _contentType;

            public Handler(Stream stream, string contentType, HttpStatusCode code)
            {
                _stream = stream;
                _code = code;
                _contentType = contentType;
            }

            protected override bool Open(CefRequest request, out bool handleRequest, CefCallback callback)
            {
                handleRequest = true;
                return true;
            }

            protected override void GetResponseHeaders(CefResponse response, out long responseLength, out string? redirectUrl)
            {
                response.Status = (int) _code;
                response.StatusText = _code.ToString();
                response.MimeType = _contentType;

                if (_stream.CanSeek)
                    responseLength = _stream.Length;
                else
                    responseLength = -1;

                redirectUrl = default;
            }

            protected override bool Skip(long bytesToSkip, out long bytesSkipped, CefResourceSkipCallback callback)
            {
                if (!_stream.CanSeek)
                {
                    bytesSkipped = -2;
                    return false;
                }

                bytesSkipped = _stream.Seek(bytesToSkip, SeekOrigin.Begin);
                return true;
            }

            protected override bool Read(Span<byte> response, out int bytesRead, CefResourceReadCallback callback)
            {
                bytesRead = _stream.Read(response);
                return bytesRead != 0;
            }

            protected override void Cancel()
            {
            }

            protected override void Dispose(bool disposing)
            {
                base.Dispose(disposing);

                _stream.Dispose();
            }
        }
    }
}
