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

namespace updateServer
{

    //롤 데이터코더로부터 경기요청 및 등록정보를 요청받는다.
    public class NetManager
    {
        const string TAG = "NETMANAGER";

        HttpListener listener = null;

        bool doListen = false;

        Thread mListenTaskWorker = null;

        ManualResetEvent mThreadCloseObserver = new ManualResetEvent(false);

        internal void stop()
        {
            doListen = false;
            listener.Stop();
            mThreadCloseObserver.WaitOne();
        }

        internal bool IsAlive()
        {


            if (mListenTaskWorker == null || !mListenTaskWorker.IsAlive)
            {
                return false;
            }
            else
            {
                return true;
            }
        }

        internal void start()
        {
            doListen = true;
            Program.mMainForm.lbServerStatus.Text = "OK";
            mListenTaskWorker = new Thread(listenTask);
            mListenTaskWorker.IsBackground = true;
            mListenTaskWorker.Start();
        }

        private void listenTask()
        {
            listener = new HttpListener();
            listener.Prefixes.Clear();
            listener.Prefixes.Add("http://+:60003/");

            listener.AuthenticationSchemes = AuthenticationSchemes.Basic | AuthenticationSchemes.Anonymous;

            listener.Start();

            while (doListen)
            {
                try
                {
                    var context = listener.GetContext();
                    HandleRequest(context);
                }
                catch (Exception ex)
                {

                }
            }


            mThreadCloseObserver.Set();

            Program.mMainForm.Invoke(new System.Windows.Forms.MethodInvoker(() => { Program.mMainForm.lbServerStatus.Text = "CLOSE"; }));

        }

        //기존에 저장한 값들을 배열로 저장하여 관리한다.
        List<string> beforeKeys = new List<string>();

        private void HandleRequest(object state)
        {

            HttpListenerContext context = (HttpListenerContext)state;

            HttpListenerRequest request = context.Request;

            string returnValue = "";

            try
            {


                if (request.RawUrl != "/favicon.ico")
                {

                    returnValue = request.RawUrl;

                    bool isTest = false;

                    var bytes = Encoding.UTF8.GetBytes(returnValue);
                    if (returnValue.Contains("/RemoveAll"))
                    {
                        UpdateManager.getInstance().RemoveAllEventRaw();
                        UpdateManager.getInstance().RemoveBackup();
                    }
                    else if (returnValue.Contains("/GameInfoGet"))
                    {
                        returnValue = UpdateManager.getInstance().GameKey + Environment.NewLine + UpdateManager.getInstance().GameName; 
                    }
                    else if (returnValue.Contains("/ConnectionGameKey"))
                    {   
                        string mPlatformKeyName = returnValue.Split(':')[1].Replace("%7C", "|").Replace("%20", " ");

                        lock (UpdateManager.getInstance().mWorkerTableLocker)
                        {
                            if (!UpdateManager.getInstance().mUpdateWorkerTable.ContainsKey(mPlatformKeyName))
                            {
                                UpdateManager.getInstance().startUpdateEventRaw(mPlatformKeyName, false);
                                returnValue = "1_" + mPlatformKeyName + "_REQUEST_START_OK_";
                            }
                            else
                            {
                                returnValue = "2_" + mPlatformKeyName + "_UPDATED_LAST";
                            }
                        }
                    }
                    ////REQUEST:게임아이디
                    else if (returnValue.Contains("/REAL") || returnValue.Contains("/TEST"))
                    {
                        Dictionary<string, string> reqValue = null;
                        if (returnValue.Contains("/REAL"))
                        {
                            isTest = false;
                        }
                        else
                        {
                            isTest = true;
                        }

                        ///라이엇에 진행중인 게임리스트를 요청
                        reqValue = UpdateManager.getInstance().GameListUpdateWorker(isTest);

                        string requestGameName = returnValue.Split(':')[1].Replace("%7C", "|").Replace("%20", " ");

                        if (reqValue.ContainsValue(requestGameName))
                        {
                            lock (UpdateManager.getInstance().mWorkerTableLocker)
                            {

                                string mPlatformKeyName = "";

                                //게임리스트에서 현재 요청받은 게임이름이 있는지 찾는다.
                                if (reqValue.Where(r => r.Value == requestGameName).Count() > 1)
                                {
                                    //이미 기존에 저장된 값이 있는지 확인하는 절차
                                    var target = reqValue.Where(r => r.Value == requestGameName);
                                    List<string> noneSavedKey = new List<string>();

                                    foreach (var v in target)
                                    {
                                        if (!beforeKeys.Contains(v.Key)) noneSavedKey.Add(v.Key);
                                    }

                                    if (noneSavedKey.Count == 1)
                                    {
                                        // 1개만 존재하면 해당 값으로 진행
                                        mPlatformKeyName = noneSavedKey[0];
                                        beforeKeys.Add(mPlatformKeyName);
                                    }
                                    else if (noneSavedKey.Count == 0)
                                    {
                                        //카운트가 0이면, target의 key 중에서 beforeKeys에 인덱스가 가장 높은 값으로 진행한다.
                                        int maxIndex = -1;
                                        foreach (var key in target.Select(x => x.Key))
                                        {
                                            int idx = beforeKeys.IndexOf(key);
                                            if (idx > maxIndex)
                                            {
                                                maxIndex = idx;
                                                mPlatformKeyName = key;
                                            }
                                        }
                                    }
                                    else
                                    {
                                        // 새로운 키가 2개 이상이면, 새로 발견된 키들을 모두 등록하고
                                        // 마지막 키를 선택 
                                        foreach (var key in noneSavedKey)
                                        {
                                            beforeKeys.Add(key);
                                        }
                                        mPlatformKeyName = noneSavedKey.Last();
                                    }

                                    //기존 방식 : 가장 최근의 값으로 진행
                                    //mPlatformKeyName = reqValue.LastOrDefault(x => x.Value == requestGameName).Key;

                                }
                                else if (reqValue.Where(r => r.Value == requestGameName).Count() == 1)
                                {
                                    mPlatformKeyName = reqValue.FirstOrDefault(x => x.Value == requestGameName).Key;
                                    if (!beforeKeys.Contains(mPlatformKeyName)) beforeKeys.Add(mPlatformKeyName);
                                }

                                //현재 받고있는 게임중에 클라이언트와 라이엇에서 요청받는게 중복되는지 확인한다.
                                if (!UpdateManager.getInstance().mUpdateWorkerTable.ContainsKey(mPlatformKeyName))
                                {
                                    UpdateManager.getInstance().startUpdateEventRaw(mPlatformKeyName, false);
                                    returnValue = "1_" + mPlatformKeyName + "_REQUEST_START_OK_";
                                }
                                else
                                {
                                    returnValue = "2_" + mPlatformKeyName + "_UPDATED_LAST";
                                }
                            }
                        }
                        //라이엇에서 클라이언트가 요청한 게임아이디가 없는경우.
                        else
                        {
                            returnValue = "3_" + requestGameName + "_CANT_FIND_GAME";
                        }

                    }
                    //클라이언트의 요청 자체가 이상한 경우.
                    else
                    {
                        returnValue = "4_" + returnValue + "_ELIGAL_REQUEST";
                    } 

                }

            }
            catch (Exception ex)
            {
                //알수없는에러
                Console.WriteLine(ex.ToString());
                returnValue = "5_BAD_SERVER_STATS_" + ex.ToString();
            }

            var rtnbytes = Encoding.UTF8.GetBytes(returnValue);

            context.Response.OutputStream.Write(rtnbytes, 0, rtnbytes.Length);
            context.Response.OutputStream.Flush();
            context.Response.OutputStream.Close();
        }

    }
}
