using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net;
using System.Threading;

namespace Rest.Net
{
    public class RouteListener
    {
        private HttpListener HttpListener = null;

        public List<Route> Routes = new List<Route>();

        public ushort Port = 8081;

        public RouteListener()
        {

        }

        public RouteListener(params Route[] routes)
        {
            this.Routes = routes.ToList();
        }

        public RouteListener(ushort port, params Route[] routes)
        {
            this.Routes = routes.ToList();

            this.Port = port;
        }

        public void Start()
        {
            if (this.HttpListener == null)
            {
                this.HttpListener = new HttpListener();

                if (Environment.OSVersion.Platform == PlatformID.Win32NT)
                {
                    this.HttpListener.Prefixes.Add($"http://localhost:{this.Port}/");
                    this.HttpListener.Prefixes.Add($"http://127.0.0.1:{this.Port}/");
                }
                else
                {
                    this.HttpListener.Prefixes.Add($"http://*:{this.Port}/");
                }

                this.HttpListener.Start();

                this.Listen();
            }
        }

        private void Listen()
        {
            ThreadPool.QueueUserWorkItem((o) =>
            {
                try
                {
                    while (this.HttpListener.IsListening)
                    {
                        ThreadPool.QueueUserWorkItem((item) =>
                        {
                            var ctx = item as HttpListenerContext;

                            try
                            {
                                bool handled = false;
                                bool close = true;
                                string[] arguments = null;
                                for (int i = 0; i < this.Routes.Count; i++)
                                {
                                    if (this.Routes[i].Method.ToUpper() == ctx.Request.HttpMethod.ToUpper() && RouteMatcher.Matches(ctx.Request.Url.AbsolutePath, this.Routes[i].Syntax, out arguments))
                                    {
                                        handled = true;
                                        close = this.Routes[i].CloseResponse;
                                        this.Routes[i].Invoke(ctx.Request, ctx.Response, arguments);
                                        break;
                                    }
                                }

                                if (!handled)
                                    ctx.Response.WithStatus(HttpStatusCode.BadRequest);

                                if (close)
                                    ctx.Response.Close();
                            }
                            catch (Exception ex)
                            {
                                ctx.Response.WithStatus(HttpStatusCode.InternalServerError);
                                ctx.Response.Close();
                            }
                        }, this.HttpListener.GetContext());
                    }
                }
                catch { }
            });
        }

        public void Stop()
        {
            if (this.HttpListener != null)
            {
                this.HttpListener.Stop();

                this.HttpListener = null;
            }
        }

        public void Block()
        {
            while (this.HttpListener != null)
                if (!Thread.Yield())
                    Thread.Sleep(1000);
        }
    }
}
