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.Linq;
using System.Threading.Tasks;
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)
        {
            return Context.InputFields
                .Where<InputField>(ip => ip.AppealTypeId == appealTypeId && ip.AppealState == state)
                .Include(p => p.SelectValues)
                .ToList();
        }

        /// <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();
            appealRecord.ItemId = ItemId;
            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();
                t.Commit();

                return response;
            }
            catch (Exception ex)
            {
                t.Rollback();
                response.Success = true;
                response.ErrorMessage = ex.Message;
                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)
            {
                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();
                    t.Commit();

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

                    response.Success = true;
                    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)
        {
            var data = Context.AppealRecords.Where<AppealRecord>(ar => ar.CreaterId == userId || (ar.ReviewerId == userId && ar.State !=1));

            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)
            {
                record.Creater.ItemStaffs = null;
                record.Creater.ReviewerItems = null;
                record.Creater.Customers = null;
                record.Item.ItemStaffs = null;
                record.Item.PreOastaff = null;
                record.Item.Reviewer = null;
            }

            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<AttachFile> GetAppealRecordAttachFiles(int appealRecordId)
        {
            var result = Context.AttachFiles.Where<AttachFile>(at => at.AppealRecordId == appealRecordId).Include(f => f.UploadUser);
            return result.ToList();
        }
    }
}
