using System;
using System.Buffers;
using System.Collections;
using System.IO;
using System.Linq;
using System.Net;
using Quik.Media;

// WebRequest is obsolete but runs on .NET framework.
#pragma warning disable SYSLIB0014

namespace Quik.Media.Stb
{
    public class StbMediaLoader : MediaLoader<string>, MediaLoader<Uri>, MediaLoader<FileInfo>, MediaLoader<FontInfo>
    {
        public bool AllowRemoteTransfers { get; set; } = false;
        private readonly ArrayPool<byte> ByteArrays = ArrayPool<byte>.Create();

        public IDisposable GetMedia(object key, MediaHint hint)
        {
            Type t = key.GetType();
            /**/ if (t == typeof(string))
            {
                return GetMedia((string)key, hint);
            }
            else if (t == typeof(Uri))
            {
                return GetMedia((Uri)key, hint);
            }
            else if (t == typeof(FileInfo))
            {
                return GetMedia((FileInfo)key, hint);
            }
            else if (t == typeof(FontInfo))
            {
                return GetMedia((FontInfo)key, hint);
            }
            else
            {
                return null;
            }
        }

        public IDisposable GetMedia(Uri uri, MediaHint hint)
        {
            throw new NotImplementedException();
        }

        public IDisposable GetMedia(string str, MediaHint hint)
        {
            throw new NotImplementedException();
        }

        public IDisposable GetMedia(FileInfo file, MediaHint hint)
        {
            throw new NotImplementedException();
        }

        public IDisposable GetMedia(FontInfo key, MediaHint hint)
        {
            throw new NotImplementedException();
        }

        public Stream OpenResource(FileInfo file)
        {
            if (file.Exists)
            {
                return file.Open(FileMode.Open);
            }
            else
            {
                return null;
            }
        }

        public Stream OpenResource(Uri uri)
        {
            switch (uri.Scheme)
            {
            case "http":
            case "https":
                if (!AllowRemoteTransfers) return null;

                try
                {
                    WebRequest request = HttpWebRequest.Create(uri);
                    WebResponse response = request.GetResponse();
                    MemoryStream stream = new MemoryStream();

                    response.GetResponseStream().CopyTo(stream);
                    response.Close();

                    stream.Position = 0;
                    return stream;
                }
                catch
                {
                    return null;
                }
            case "file":
                return OpenResource(new FileInfo(uri.AbsolutePath));
            default:
                return null;
            }
        }

        public Stream OpenResource(string key)
        {
            if (File.Exists(key))
            {
                return File.Open(key, FileMode.Open);
            }
            else if (Uri.TryCreate(key, UriKind.RelativeOrAbsolute, out Uri uri))
            {
                return OpenResource(uri);
            }
            else
            {
                return null;
            }
        }

        MediaHint InferMedia(Stream str, MediaHint hint)
        {
            if (hint != MediaHint.None)
            {
                return hint;
            }

            byte[] array = ByteArrays.Rent(4);
            str.Read(array, 0, 4);
            str.Position = 0;

            foreach (var(type, seq) in MediaTypes)
            {
                if (seq.SequenceEqual(array))
                    return hint;
            }

            return MediaHint.None;
        }

        private readonly (MediaHint, byte[])[] MediaTypes = new (MediaHint, byte[])[] {
            (MediaHint.Image, new byte[] { 0x42, 0x4d }),               /* .bmp `BM` */
            (MediaHint.Image, new byte[] { 0x47, 0x49, 0x46, 0x38 }),   /* .gif `GIF8` */
            (MediaHint.Image, new byte[] { 0xff, 0xd8, 0xff, 0xe0 }),   /* .jpg (JFIF) */
            (MediaHint.Image, new byte[] { 0xff, 0xd8, 0xff, 0xe1 }),   /* .jpg (EXIF) */
            (MediaHint.Image, new byte[] { 0x89, 0x50, 0x4e, 0x47 }),   /* .png `.PNG `*/
            (MediaHint.Image, new byte[] { 0x4d, 0x4d, 0x00, 0x2a }),   /* .tif (motorola) */
            (MediaHint.Image, new byte[] { 0x49, 0x49, 0x2a, 0x00 }),   /* .tif (intel) */
            (MediaHint.Font, new byte[] { 0x00, 0x01, 0x00, 0x00 }),    /* .ttf */
            (MediaHint.Font, new byte[] { 0x4F, 0x54, 0x54, 0x4F }),    /* .otf */
        };
    }
}
