using System;
using System.Collections.Specialized;
using System.IO;
using System.Text;
using CefSharp;
using CefSharp.Callback;

namespace TweetDuck.Browser.Handling {
	sealed class ResourceHandlerNotification : IResourceHandler {
		private readonly NameValueCollection headers = new NameValueCollection(0);
		private MemoryStream dataIn;

		public void SetHTML(string html) {
			dataIn?.Dispose();
			dataIn = ResourceHandler.GetMemoryStream(html, Encoding.UTF8);
		}

		public void Dispose() {
			if (dataIn != null) {
				dataIn.Dispose();
				dataIn = null;
			}
		}

		bool IResourceHandler.Open(IRequest request, out bool handleRequest, ICallback callback) {
			callback.Dispose();
			handleRequest = true;

			if (dataIn != null) {
				dataIn.Position = 0;
			}

			return true;
		}

		void IResourceHandler.GetResponseHeaders(IResponse response, out long responseLength, out string redirectUrl) {
			redirectUrl = null;

			response.MimeType = "text/html";
			response.StatusCode = 200;
			response.StatusText = "OK";
			response.Headers = headers;
			responseLength = dataIn?.Length ?? 0;
		}

		bool IResourceHandler.Read(Stream dataOut, out int bytesRead, IResourceReadCallback callback) {
			callback?.Dispose(); // TODO unnecessary null check once ReadResponse is removed

			try {
				byte[] buffer = new byte[Math.Min(dataIn.Length - dataIn.Position, dataOut.Length)];
				int length = buffer.Length;

				dataIn.Read(buffer, 0, length);
				dataOut.Write(buffer, 0, length);
				bytesRead = length;
			} catch { // catch IOException, possibly NullReferenceException if dataIn is null
				bytesRead = 0;
			}

			return bytesRead > 0;
		}

		bool IResourceHandler.Skip(long bytesToSkip, out long bytesSkipped, IResourceSkipCallback callback) {
			bytesSkipped = -2; // ERR_FAILED
			callback.Dispose();
			return false;
		}

		bool IResourceHandler.ProcessRequest(IRequest request, ICallback callback) {
			return ((IResourceHandler) this).Open(request, out bool _, callback);
		}

		bool IResourceHandler.ReadResponse(Stream dataOut, out int bytesRead, ICallback callback) {
			return ((IResourceHandler) this).Read(dataOut, out bytesRead, null);
		}

		void IResourceHandler.Cancel() {}
	}
}