using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net;
using System.IO;
using MontoyaTech.Rest.Net;
using System.Net.Mime;

namespace MontoyaTech.Rest.Net.Example
{
    public class Program
    {
        public class BaseUser
        {
            public string Id;

            public UserRole Role { get; set; }

            public List<Permission> Permissions;

            public class Permission
            {
                public string Name;

                public Types Type;

                public enum Types { Read, Write }
            }
        }

        public class User : BaseUser
        {
            public string Name = null;

            public List<string> List = null;

            public ulong Property { get; set; }

            public User() { }

            public User(string name)
            {
                this.Name = name;
            }
        }

        public enum UserRole : byte
        {
            Unknown = 0,
            Admin = 2,
            User = 1
        }

        public class IncludedType
        {
            public int Test;
        }

        public static RouteFileCache FileCache = new RouteFileCache(100 * 1024 * 1024);

        public static void Main(string[] args)
        {
            File.WriteAllText("test.txt", "hello from a file");

            var listener = new RouteListener(8080,
                new Route(HttpRequestMethod.Get, "/status", Status),
                new Route<double, double>(HttpRequestMethod.Post, "/add/{a}/{b}", Add),
                new Route(HttpRequestMethod.Get, "/compress", Compress),
                new Route(HttpRequestMethod.Get, "/file/compress", CompressFile),
                new Route<string>(HttpRequestMethod.Get, "/auth/{username}", Exists),
                new Route(HttpRequestMethod.Post, "/auth/signup", Signup),
                new Route(HttpRequestMethod.Get, "/auth/", Json),
                new Route(HttpRequestMethod.Get, "/auth/role", GetRole)
            );

            string code = listener.GenerateCSharpClient();

            Console.WriteLine(code);
            Console.WriteLine();

            string staticCode = listener.GenerateCSharpClient("StaticClient", staticCode: true);

            Console.WriteLine(staticCode);

            listener.RequestPreProcessEvent += (HttpListenerContext context) => {
                Console.WriteLine($"[{context.Request.HttpMethod}] Request start: " + context.Request.RawUrl);
                return true;
            };

            listener.RequestPostProcessEvent += (HttpListenerContext context) =>
            {
                Console.WriteLine($"[{context.Request.HttpMethod}] Request end: " + context.Request.RawUrl);
            };

            listener.Start();

            Console.WriteLine("Available routes:");

            foreach (var route in listener.Routes)
                Console.WriteLine($"- [{route.Method}] {route.Syntax}");

            Console.WriteLine($"Rest api server running at {listener.BaseUrl}");

            listener.Block();
        }

        [RouteGroup("Test")]
        [RouteResponse(typeof(string))]
        [RouteInclude(typeof(IncludedType))]
        public static HttpListenerResponse Status(HttpListenerContext context)
        {
            return context.Response.WithStatus(HttpStatusCode.OK).WithText("Everything is operational. 👍");
        }

        [RouteGroup("Test")]
        [RouteResponse(typeof(string))]
        public static HttpListenerResponse Add(HttpListenerContext context, double a, double b)
        {
            return context.Response.WithStatus(HttpStatusCode.OK).WithText((a + b).ToString());
        }

        [RouteGroup("Test")]
        [RouteResponse(typeof(string))]
        public static HttpListenerResponse Compress(HttpListenerContext context)
        {
            return context.Response.WithStatus(HttpStatusCode.OK).WithCompressedText("hello world");
        }

        [RouteGroup("Test")]
        [RouteResponse(typeof(string))]
        public static HttpListenerResponse CompressFile(HttpListenerContext context)
        {
            var content = FileCache.Cache("test.txt");

            return context.Response.WithStatus(HttpStatusCode.OK).WithCompressedFile("test.txt", content);
        }

        [RouteGroup("Test")]
        [RouteRequest(typeof(User))]
        public static HttpListenerResponse SignupRequest(HttpListenerContext context)
        {
            return context.Response.WithStatus(HttpStatusCode.OK);
        }

        [RouteGroup("Auth")]
        [RouteName("UserExists")]
        [RouteResponse(typeof(bool), Json = false)]
        public static HttpListenerResponse Exists(HttpListenerContext context, string name)
        {
            Console.WriteLine("Auth.Exists called, name:" + name);

            return context.Response.WithStatus(HttpStatusCode.OK).WithText("true");
        }

        [RouteGroup("Auth")]
        [RouteRequest(typeof(User))]
        public static HttpListenerResponse Signup(HttpListenerContext context)
        {
            return context.Response.WithStatus(HttpStatusCode.OK);
        }

        [RouteGroup("Auth")]
        [RouteResponse(typeof(UserRole))]
        public static HttpListenerResponse GetRole(HttpListenerContext context)
        {
            return context.Response.WithStatus(HttpStatusCode.OK).WithJson(UserRole.Admin);
        }

        [RouteGroup("Auth")]
        [RouteName("Get")]
        [RouteResponse(typeof(User))]
        public static HttpListenerResponse Json(HttpListenerContext context)
        {
            return context.Response.WithStatus(HttpStatusCode.OK).WithJson(new User("Rest.Net"));
        }
    }
}