using FactorySystemBll;
using FactorySystemCommon;
using FactorySystemModel.BusinessModel;
using FactorySystemModel.EnumModel;
using FactorySystemModel.ResponseModel;
using FactorySystemModel.SqlSugarModel;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Web.Http.Controllers;
using System.Web.Http.Filters;
using System.Xml;

namespace FactorySystemApi
{
    /// <summary>
    /// 授权
    /// </summary>
    public class UserLoginFilter : AuthorizationFilterAttribute
    {
        /// <summary>
        /// 指示指定的控件是否已获得授权
        /// </summary>
        public override void OnAuthorization(HttpActionContext actionContext)
        {
            try
            {
                //验证Referrer
                string ApiRealNameUrl = AppSettingsHelper.GetAppSettingVal("ApiRealNameUrl");
                if (!string.IsNullOrEmpty(ApiRealNameUrl))
                {
                    string[] ApiRealNameUrls = ApiRealNameUrl.Split(',');
                    string requestHost = actionContext.Request.Headers.Referrer.Host;
                    bool isRealUrl = false;
                    for (int i = 0; i < ApiRealNameUrls.Length && !isRealUrl; i++)
                    {
                        Uri apiUrl = new Uri(ApiRealNameUrls[i]);
                        if (apiUrl.Host == requestHost) isRealUrl = true;
                    }
                    if (!isRealUrl) throw new Exception("请求失败，不在授权访问内");
                }
                //验证接口配置
                if (actionContext.ControllerContext.ControllerDescriptor.GetCustomAttributes<UserLoginFilter>().Count > 0)
                {
                    if (actionContext.ActionDescriptor.GetCustomAttributes<NoCheckUserLogin>().Count > 0) { return; }
                }
                else { return; }

                string token = "";
                //前端请求api时会将token存放在名为"auth"的请求头中
                var authHeader = from t in actionContext.Request.Headers where t.Key == "token" select t.Value.FirstOrDefault();
                if (authHeader == null || string.IsNullOrEmpty(token = authHeader.FirstOrDefault()))
                {
                    authHeader = from t in actionContext.Request.Headers where t.Key == "ticket" select t.Value.FirstOrDefault();
                    if (authHeader != null && !string.IsNullOrEmpty(token = authHeader.FirstOrDefault()))
                    {
                        token = CasLogin(token, AppSettingsHelper.GetAppSettingVal("Cas_ReUrl"));
                        actionContext.Request.Properties.Add("reticket", token);
                    }
                    else
                    {
                        throw new Exception("登录超时，请重新登录");
                    }
                }

                //解密
                ApiAuthInfo authInfo = JWTHelper.Decrypt<ApiAuthInfo>(token);
                if (authInfo == null || !DateTime.TryParse(authInfo.FExpireTime, out DateTime expireTime) || DateTime.Compare(expireTime, DateTime.Now) < 0)
                {
                   throw new Exception("登录超时，请重新登录");
                }
                actionContext.Request.Properties.Add("token", authInfo);
            }
            catch (Exception ex)
            {
                string errorMsg = string.Format("{1}", Environment.NewLine, ex.Message.ToString());
                ExceptionHelper.WriteMessage(errorMsg, 2);
                ApiResult errResult = new ApiResult().CustomError((int)Constant.ApiResultCode.异常, errorMsg);
                if (ex.Message == "登录超时，请重新登录")
                {
                    errResult.Ticket = AppSettingsHelper.GetAppSettingVal("Cas_OAUrl") + "login?appid=testsso&service=" + AppSettingsHelper.GetAppSettingVal("Cas_ReUrl");
                }
                string tempStr = JsonConvert.SerializeObject(errResult);
                actionContext.Response = new HttpResponseMessage() { Content = new StringContent(tempStr, Encoding.GetEncoding("UTF-8"), "application/json") };
            }
        }


        /// <summary>
        /// OA登录信息对接
        /// </summary>
        private string CasLogin(string ticket, string refUrl)
        {
            string valUrl = AppSettingsHelper.GetAppSettingVal("Cas_OAUrl");
            valUrl += string.Format(@"serviceValidate?ticket={0}&service={1}", ticket, refUrl);
            try
            {
                StreamReader Reader = new StreamReader(new WebClient().OpenRead(valUrl));
                string resp = Reader.ReadToEnd();
                ExceptionHelper.AddSystemJournal(null, valUrl, resp, -1, "CasLoginLog");
                XmlDocument xmlDoc = new XmlDocument();
                xmlDoc.LoadXml(resp);

                string userid = "";
                XmlNamespaceManager nsmgr = new XmlNamespaceManager(xmlDoc.NameTable);
                nsmgr.AddNamespace("cas", "http://www.yale.edu/tp/cas");
                if (xmlDoc.SelectSingleNode("/cas:serviceResponse/cas:authenticationSuccess/cas:attributes", nsmgr) != null)
                {
                    XmlNode root = xmlDoc.SelectSingleNode("/cas:serviceResponse/cas:authenticationSuccess/cas:attributes", nsmgr);
                    userid = root.SelectSingleNode("cas:workcode", nsmgr) == null ? "" : root.SelectSingleNode("cas:workcode", nsmgr).InnerText;
                }
                if (!string.IsNullOrEmpty(userid))
                {
                    TUser user = BaseBll.GetTempModel<TUser>(string.Format("FDockID='{0}'", userid.Replace("'", "\"")));
                    if (user != null)
                    {
                        ApiAuthInfo apiAuthInfo = new ApiAuthInfo()
                        {
                            FID = user.FID,
                            FName = user.FName,
                            FUser = user.FUser,
                            FExpireTime = DateTime.Now.AddDays(30).ToString("yyyy-MM-dd HH:mm:ss")
                        };

                        Dictionary<string, object> updateModel = new Dictionary<string, object>();
                        updateModel.Add("FID", user.FID);
                        updateModel.Add("FLoginDate", DateTime.Now);
                        BaseBll.UpdateDataModel(updateModel, "TUser");

                        return JWTHelper.Encryption(apiAuthInfo);
                    }
                }
            }
            catch (Exception ex)
            {
                ExceptionHelper.AddSystemJournal(null, valUrl, ex.Message, -1, "CasLoginLog");
                throw new Exception("OA获取用户信息报错，请重新登录");
            }
            throw new Exception("登录超时，请重新登录");
        }
    }

    /// <summary>
    /// 不需要授权
    /// </summary>
    public class NoCheckUserLogin : Attribute
    { }
}