using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text.Json.Serialization;
using System.Text.Json;
using System.Threading.Tasks;
using wispro.sp.api.Job;
using wispro.sp.entity;
using wispro.sp.share;

namespace wispro.sp.api.Controllers
{
    [Route("api/[controller]/[action]")]
    [ApiController]
    [Authorize]
    public class AppealController : ControllerBase
    {
        spDbContext Context;

        public AppealController(spDbContext context)
        {
            Context = context;
        }

        public List<AppealType> GetAppealTypes()
        {
            return Context.AppealTypes.ToList();
        }

        public List<InputField> GetInputField(int appealTypeId, int state)
        {
            var retList = Context.InputFields
                .Where<InputField>(ip => ip.AppealTypeId == appealTypeId && ip.AppealState == state)
                .Include(p => p.SelectValues)
                .ToList();

            string str = System.Text.Json.JsonSerializer.Serialize(retList, new JsonSerializerOptions()
            {
                ReferenceHandler = ReferenceHandler.Preserve
            });
            Log(str);
            foreach (var inputField in retList)
            {
                if (inputField.SelectValues != null)
                {
                    foreach(var ifValue in inputField.SelectValues)
                    {
                        ifValue.InputField = null;
                    }
                }
            }

            return retList;
        }

        /// <summary>
        /// 创建申诉流程
        /// </summary>
        /// <param name="ItemId"></param>
        /// <param name="typeid"></param>
        /// <param name="reviewerId"></param>
        /// <param name="appealObject"></param>
        /// <returns></returns>
        public ApiSaveResponse CreateAppeal(int ItemId, int typeid, int reviewerId, AppealObject appealObject)
        {
            ApiSaveResponse response = new ApiSaveResponse();
            response.Success = true;
            
            AppealRecord appealRecord = new AppealRecord();
            if(ItemId > 0)
            {
                appealRecord.ItemId = ItemId;
            }
            else
            {
                appealRecord.ItemId = null;
            }
            
            appealRecord.TypeId = typeid;
            appealRecord.ReviewerId = reviewerId;
            appealRecord.CreaterId =  Context.Staffs.Where<Staff>(s => s.Name == User.Identity.Name).FirstOrDefault().Id;
            appealRecord.CreateTime = DateTime.Now;

            var t = Context.Database.BeginTransaction();
            try
            {
                Context.AppealRecords.Add(appealRecord);
                Context.SaveChanges();
                foreach (var fieldValue in appealObject.inputFieldValues)
                {
                    fieldValue.InputField = null;
                    fieldValue.AppealRecordId = appealRecord.Id;
                }
                Context.InputFieldValues.AddRange(appealObject.inputFieldValues);

                foreach (var file in appealObject.attachFiles)
                {
                    var temFile = Context.AttachFiles.Where<AttachFile>(f => f.Id == file.Id).FirstOrDefault();
                    temFile.AppealRecordId = appealRecord.Id;
                    temFile.UploadUserId = appealRecord.CreaterId;
                }

                Context.SaveChanges();

                var temType = Context.AppealTypes.FirstOrDefault(c=>c.Id == appealRecord.TypeId);
                if (!string.IsNullOrEmpty(temType.ApplealObject))
                {
                    IDoAppealObject doAppeal = (IDoAppealObject)Activator.CreateInstance(Type.GetType(appealRecord.Type.ApplealObject));
                    doAppeal.DoAppeal(appealObject, appealRecord.Id, Context);
                }

                t.Commit();

                var Reviewer = Context.Staffs.Where<Staff>(s => s.Id == appealRecord.ReviewerId).FirstOrDefault();

                if(appealRecord.Type == null)
                {
                    appealRecord.Type = Context.AppealTypes.FirstOrDefault(p=>p.Id == appealRecord.TypeId);
                }

                string strSubject = appealRecord.Type.Name;
                string strBody = $"<div style=\"position:absolute;width:800;height:300;margin-top:50px;margin-left:200px;margin-right:200px;box-shadow:0px 0px 3px 3px #ccc \"><div style= \"margin-top: 20px; margin-left:20px;;font-size:14px; \">{Reviewer.Name},您好！</div><div style= \"margin-top: 25px; margin-left:20px;font-size:14px; \"><div>{User.Identity.Name} 向您提交了{appealRecord.Type.Name}申诉，请使用<a href= \"http://1.116.113.26\">绩效系统</a>在<B>{utility.ConfigHelper.GetSectionValue("Lastest_feedback_date")}日</B>前完成审核！</div><div style= \"margin-top: 100px;margin-right:15px; padding-bottom: 20px; font-size:14px;color:#888888;float:right; \">小美集团绩效管理系统</div></div>";
                string strTo = Reviewer.Mail;

                if (!string.IsNullOrEmpty(strTo))
                {
                    _ = QuartzUtil.AddMailJob(strSubject, strBody, Reviewer.Name, strTo);
                }

                strBody = $"<div style=\"position:absolute;width:800;height:300;margin-top:50px;margin-left:200px;margin-right:200px;box-shadow:0px 0px 3px 3px #ccc \"><div style= \"margin-top: 20px; margin-left:20px;;font-size:14px; \">{Reviewer.Name},您好！</div><div style= \"margin-top: 25px; margin-left:20px;font-size:14px; \"><div>{User.Identity.Name} 向您提交了{appealRecord.Type.Name}申诉，请使用<a href= \"http://1.116.113.26\">绩效系统</a>查看详情！</div><div style= \"margin-top: 100px;margin-right:15px; padding-bottom: 20px; font-size:14px;color:#888888;float:right; \">小美集团绩效管理系统</div></div>";
                _ = QuartzUtil.AddMailJob(strSubject, strBody, "钟子敏", "zhongzimin@china-wispro.com");
                _ = QuartzUtil.AddMailJob(strSubject, strBody, "夏敏", "xiamin@china-wispro.com");
                _ = QuartzUtil.AddMailJob(strSubject, strBody, "吴芳", "wufang@china-wispro.com");

                return response;
            }
            catch (Exception ex)
            {
                t.Rollback();
                response.Success = false;
                response.ErrorMessage = "申诉时发生错误！";
                return response;
            }
        }

        public ApiSaveResponse ReviewerAppeal(int appealRecordId,AppealObject appealObject)
        {
            ApiSaveResponse response = new ApiSaveResponse();
            response.Success = true;

            var appealRecord = Context.AppealRecords.Where<AppealRecord>(p => p.Id == appealRecordId).FirstOrDefault();

            
            if(appealRecord != null)
            {
                if (appealRecord.ItemId.HasValue)
                {
                    var item = Context.PerformanceItems.Include(p=>p.CalMonth).FirstOrDefault(p => p.Id == appealRecord.ItemId.Value);

                    if(item == null)
                    {
                        response.Success = false;
                        response.ErrorMessage = "无效的ItemId!";
                        return response;
                    }
                    else
                    {
                        if(item.CalMonth.Status != 0)
                        {
                            response.Success = false;
                            response.ErrorMessage = "指定的绩效已经归档！";
                            return response;
                        }
                    }
                }

                var t = Context.Database.BeginTransaction();
                try
                {
                    appealRecord.ReviewerId = Context.Staffs.Where<Staff>(s => s.Name == User.Identity.Name).FirstOrDefault().Id;
                    appealRecord.State = 1;
                    appealRecord.ReviewTime = DateTime.Now;

                    Context.SaveChanges();
                    foreach (var fieldValue in appealObject.inputFieldValues)
                    {
                        fieldValue.InputField = null;
                        fieldValue.AppealRecordId = appealRecord.Id;
                    }
                    Context.InputFieldValues.AddRange(appealObject.inputFieldValues);
                    Context.SaveChanges();
                    if (appealObject.attachFiles != null)
                    {
                        foreach (var file in appealObject.attachFiles)
                        {
                            var temFile = Context.AttachFiles.Where<AttachFile>(f => f.Id == file.Id).FirstOrDefault();
                            temFile.AppealRecordId = appealRecord.Id;
                            temFile.UploadUserId = appealRecord.ReviewerId;
                        }
                    }

                    List<InputFieldValue> inputFieldValues = Context.InputFieldValues
                        .Where<InputFieldValue>(p => p.AppealRecordId == appealRecordId
                                    && p.InputField.MapObjectField != null)
                        .Include(i=>i.InputField)
                        .ToList();

                    foreach(InputFieldValue inputFieldValue in inputFieldValues)
                    {
                        
                        SaveValueToMapObject(appealRecord, inputFieldValue);
                        
                    }

                    Context.SaveChanges();

                    if(appealRecord.Type == null)
                    {
                        appealRecord.Type = Context.AppealTypes.FirstOrDefault(s=>s.Id == appealRecord.TypeId);
                    }

                    if (!string.IsNullOrEmpty(appealRecord.Type.ReviewObject))
                    {
                        IDoAppealObject doAppeal = (IDoAppealObject)Activator.CreateInstance(Type.GetType(appealRecord.Type.ReviewObject));

                        doAppeal.DoAppeal(appealObject, appealRecord.Id,Context);
                    }

                    Context.SaveChanges();

                    if(appealRecord.ItemId.HasValue)
                    {
                        var item = Context.PerformanceItems
                            .Include(p => p.ItemStaffs)
                            .Include(p => p.Customer)
                            .Include(p=>p.Reviewer)
                            .FirstOrDefault(p=>p.Id == appealRecord.ItemId);
                        new PerformanceItemController(Context, new Services.FileTaskCacheService()).RefreshPoint(item);
                    }
                    
                    t.Commit();

                    return response;
                }
                catch (Exception ex)
                {
                    t.Rollback();

                    response.Success = false;
                    response.ErrorMessage = ex.Message;
                    return response;
                }
            }
            else
            {
                response.Success = true;
                response.ErrorMessage = "申诉不存在！";
                return response;
            }
            
        }

        private object ConvertSimpleType(object value, Type destinationType)
        {
            object returnValue;
            if ((value == null) || destinationType.IsInstanceOfType(value))
            {
                return value;
            }
            string str = value as string;
            if ((str != null) && (str.Length == 0))
            {
                return null;
            }
            TypeConverter converter = TypeDescriptor.GetConverter(destinationType);
            bool flag = converter.CanConvertFrom(value.GetType());

            if (!flag)
            {
                converter = TypeDescriptor.GetConverter(value.GetType());
            }
            if (!flag && !converter.CanConvertTo(destinationType))
            {
                throw new InvalidOperationException("无法转换成类型：" + value.ToString() + "==>" + destinationType);
            }
            try
            {
                returnValue = flag ? converter.ConvertFrom(null, null, value) : converter.ConvertTo(null, null, value, destinationType);
            }
            catch (Exception e)
            {
                throw new InvalidOperationException("类型转换出错：" + value.ToString() + "==>" + destinationType, e);
            }
            return returnValue;
        }



        private void SaveValueToMapObject(AppealRecord appealRecord, InputFieldValue inputFieldValue)
        {
            if (!string.IsNullOrEmpty(inputFieldValue.InputField.MapObjectField))
            {
                bool isSave = false;
                if (!string.IsNullOrEmpty(inputFieldValue.InputField.MapSaveCondition))
                {
                    string[] conditions = inputFieldValue.InputField.MapSaveCondition.Split(new char[] { ':' }, StringSplitOptions.RemoveEmptyEntries);

                    if (conditions.Length == 1)
                    {
                        if (appealRecord.State == int.Parse(conditions[0]))
                        {
                            isSave = true;
                        }
                    }
                    else
                    {
                        if (appealRecord.State == int.Parse(conditions[0]))
                        {
                            InputFieldValue temValue =
                            Context.InputFieldValues.Where<InputFieldValue>(v =>
                                v.AppealRecordId == appealRecord.Id &&
                                v.InputField.Id == int.Parse(conditions[1]) &&
                                v.Value == conditions[2])
                            .FirstOrDefault();

                            if (temValue != null)
                            {
                                isSave = true;
                            }
                        }
                    }

                }
                else
                {
                    isSave = true;
                }

                if (isSave)
                {
                    InputField field = inputFieldValue.InputField;
                    PerformanceItem Item = Context.PerformanceItems.Where<PerformanceItem>(p =>
                        p.Id == appealRecord.ItemId)
                        .Include(p => p.ItemStaffs).ThenInclude(it=>it.DoPerson)
                        .Include(p => p.Reviewer)
                        .FirstOrDefault();

                    bool ItemIsNull = false;
                    if(Item == null)
                    {
                        ItemIsNull = true;
                        Item = new PerformanceItem();
                    }

                    if (!string.IsNullOrEmpty(field.MapObjectField) && !string.IsNullOrEmpty(field.MapObjectFieldLabel))
                    {
                        List<InputFieldValue> temValues = new List<InputFieldValue>();
                        string[] pList = field.MapObjectField.Split(new char[] { '.' });
                        string[] plList = field.MapObjectFieldLabel.Split(new char[] { '.' });

                        var pInfo = Item.GetType().GetProperty(pList[0]);

                        var o = pInfo.GetValue(Item);


                        if (Array.IndexOf(o.GetType().GetInterfaces(), typeof(IEnumerable)) > -1)
                        {
                            List<string> Values = new List<string>();
                            List<string> Labels = new List<string>();

                            var objList = o as IEnumerable;

                            foreach (var obj in objList)
                            {
                                var objLabel = obj;
                                for (int i = 1; i < plList.Length; i++)
                                {
                                    objLabel = objLabel.GetType().GetProperty(plList[i]).GetValue(objLabel);
                                }

                                if (objLabel.ToString() == inputFieldValue.Label)
                                {
                                    var objValue = obj;

                                    for (int i = 1; i < pList.Length - 1; i++)
                                    {
                                        objValue = objValue.GetType().GetProperty(pList[i]).GetValue(objValue);
                                    }

                                    objValue.GetType().GetProperty(pList[pList.Length - 1])
                                        .SetValue(objValue, ConvertSimpleType(inputFieldValue.Value,Type.GetType(inputFieldValue.InputField.FieldType)));
                                }
                            }
                        }
                        
                    }
                    else
                    {
                        Item.GetType().GetProperty(field.MapObjectField).SetValue(Item, ConvertSimpleType(inputFieldValue.Value, Type.GetType(inputFieldValue.InputField.FieldType)));

                    }

                }
            }
        }



        public List<AppealRecord> GetAppealRecords(int userId)
        {
            try
            {
                var data = Context.AppealRecords.Where<AppealRecord>(p => p.Id > 0);
                if (userId > 0)
                {
                    data = Context.AppealRecords.Where<AppealRecord>(ar => (ar.CreaterId == userId || (ar.ReviewerId == userId && ar.State != 1)) && ar.Type.NeedReview == true);
                }

                var retList = data
                    //.Include(p => p.Reviewer)
                    .Include(p => p.Creater)
                    .Include(p => p.Item)
                    .Include(p => p.Type)
                    .ToList();
                

                foreach (var record in retList)
                {
                    replaceDataForSerialize(record);
                }

                //string str = System.Text.Json.JsonSerializer.Serialize(retList);
                //System.Diagnostics.Debug.WriteLine(str);
                //Log(str);

                return retList;
            }
            catch (Exception ex)
            {
                Log(ex.ToString());
                return new List<AppealRecord>();
            }
            
        }

        private  void replaceDataForSerialize(AppealRecord record)
        {
            if(record.Creater !=null)
            {
                Staff temStaff = new Staff()
                {
                    Name = record.Creater.Name,
                    Id = record.Creater.Id,
                    ItemStaffs = null,
                    ReviewerItems = null,
                    Customers = null,
                    Positions = null,
                    StaffGrade = null,
                };

                record.Creater = temStaff;
                //record.Creater.ItemStaffs = null;
                //record.Creater.ReviewerItems = null;
                //record.Creater.Customers = null;
                //record.Creater.Positions = null;
                //record.Creater.StaffGrade = null;
            }

            if (record.Reviewer != null)
            {
                Staff temStaff = new Staff() { 
                    Name = record.Reviewer.Name,
                    Id = record.Creater.Id,
                    ItemStaffs = null,
                    ReviewerItems = null,
                    Customers = null,
                    Positions = null,
                    StaffGrade = null,
                };

                record.Reviewer = temStaff;

                //record.Reviewer.ItemStaffs = null;
                //record.Reviewer.Customers = null;
                //record.Reviewer.ReviewerItems = null;
                //record.Reviewer.Positions = null;
                //record.Reviewer.StaffGrade = null;
            }

            if (record.Item != null)
            {
                PerformanceItem temItem = new PerformanceItem()
                {
                    Id = record.Item.Id,
                    CaseNo = record.Item.CaseNo,
                    CaseName = record.Item.CaseName,
                    CalMonthId = record.Item.CalMonthId
                    
                };

                record.Item = temItem;

                //record.Item.ItemStaffs = null;
                //record.Item.PreOastaff = null;
                //record.Item.Reviewer = null;
                //record.Item.WorkflowUser = null;
                //record.Item.Customer = null;
                //record.Item.CalMonth = null;
            }

            if(record.Type != null)
            {
                record.Type.ReviewerExpress = null;
                record.Type.CanDoExpress = null;
                record.Type.ApplealObject = null;
                record.Type.CanDoExpress = null;
                record.Type.ReviewerExpress = null;
            }
            //record.Type.ReviewerExpress = null;
        }

        [HttpPost]
        public List<AppealRecord> QueryByFilter(AppealRecordFilter filter)
        {
            var data = Context.AppealRecords.Where<AppealRecord>(s => true);
            if(filter.AppealTypeId > 0)
            {
                data = Context.AppealRecords.Where(f=>f.TypeId == filter.AppealTypeId);
            }

            if(!string.IsNullOrEmpty(filter.CaseNo))
            {
                data = data.Where(s=>s.Item.CaseNo.Contains(filter.CaseNo));
            }

            if (!string.IsNullOrEmpty(filter.CreateUser))
            {
                data = data.Where(s => s.Creater.Name.Contains(filter.CreateUser));
            }

            if (!string.IsNullOrEmpty(filter.Reviewer))
            {
                data = data.Where(s => s.Reviewer.Name.Contains(filter.Reviewer));
            }

            if (filter.beginCreateTime.HasValue)
            {
                data = data.Where(s => s.CreateTime>=filter.beginCreateTime.Value  );
            }

            if (filter.endCreateTime.HasValue)
            {
                data = data.Where(s => s.CreateTime <= filter.endCreateTime.Value);
            }

            if (filter.beginReviewTime.HasValue)
            {
                data = data.Where(s => s.ReviewTime >= filter.beginReviewTime.Value);
            }

            if (filter.endReviewTime.HasValue)
            {
                data = data.Where(s => s.ReviewTime <= filter.endReviewTime.Value);
            }

            var retList = data
                .Include(p => p.Reviewer)
                .Include(p => p.Creater)
                .Include(p => p.Item)
                .Include(p => p.Type)
                .ToList();

            foreach (var record in retList)
            {
                replaceDataForSerialize(record);
            }

            return retList;
        }

        public AppealRecord GetAppealRecord(int Id)
        {
            var data = Context.AppealRecords.Where<AppealRecord>(ar => ar.Id == Id);

            return data.Include(p => p.Reviewer)
                .Include(p => p.Creater)
                .Include(p => p.Item)
                .Include(p => p.Type).FirstOrDefault();
        }

        public List<InputFieldValue> GetInputFieldValues(int id, int state)
        {
            var result = Context.InputFieldValues.Where<InputFieldValue>(f => f.AppealRecordId == id && f.InputField.AppealState == state);
            return result.Include(i => i.InputField).ToList();
        }

        public List<InputFieldValue> GetAllInputFieldValue(int id)
        {
            var result = Context.InputFieldValues.Where<InputFieldValue>(f => f.AppealRecordId == id);
            return result.Include(i => i.InputField).ToList();
        }

        public List<AttachFile> GetAppealRecordAttachFiles(int appealRecordId)
        {
            var result = Context.AttachFiles.Where<AttachFile>(at => at.AppealRecordId == appealRecordId).Include(f => f.UploadUser);
            return result.ToList();
        }

        public ApiSaveResponse ChangeRecordReviewer(int RecordId,int ReviewerId)
        {
            var data = Context.AppealRecords.FirstOrDefault<AppealRecord>(ar => ar.Id == RecordId);

            if(data != null)
            {
                var reviewer = Context.Staffs.FirstOrDefault(s => s.Id == ReviewerId);

                var CurrentUser = Context.Staffs.FirstOrDefault(s=>s.Name == User.Identity.Name);

                if ((CurrentUser.Id == data.CreaterId || CurrentUser.Id == data.ReviewerId) && data.State ==0)
                {

                    if (reviewer != null)
                    {
                        data.ReviewerId = ReviewerId;
                        Context.SaveChanges();

                        return new ApiSaveResponse()
                        {
                            Success = true
                        };
                    }
                    else
                    {
                        return new ApiSaveResponse()
                        {
                            Success = false,
                            ErrorMessage = "指定的审核人不存在"
                        };
                    }
                }
                else
                {
                    return new ApiSaveResponse()
                    {
                        Success = false,
                        ErrorMessage = "只有申诉人和审核人在未审核状态时才能变更审核人"
                    };
                }
            }
            else
            {
                return new ApiSaveResponse()
                {
                    Success = false,
                    ErrorMessage = "指定的申诉记录不存在"
                };
            }
        }

        private void Log(string strMessage)
        {
            StreamWriter sw = System.IO.File.AppendText("c:\\temp\\log.txt");
            sw.WriteLine($"{strMessage}");
            sw.Flush();
            sw.Close();
            sw.Dispose();
        }


    }
}
