using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.StaticFiles;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using wispro.sp.entity;
using wispro.sp.entity.workflowInstance;
using wispro.sp.share;
using wispro.sp.share.Utility;

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

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

        public void DoAction(int instanceId,int stepId,int ActionId,List<InputValue> inputValues)
        {
            //1、取实例对象

            //2、取步骤对象

            //3、判断Action定义对象

            //4、判断输入值合法性

            //5、保存数据
        }

        [HttpPost]
        public ApiSaveResponse AddNew(NewWorkflowObject workflowObject)
        {
            ApiSaveResponse ret = new ApiSaveResponse();
            ret.Success = true;

            using(var t = Context.Database.BeginTransaction())
            {
                try
                {
                    if (workflowObject.InitAction != null)
                    {
                        Context.Actions.Add(workflowObject.InitAction.Action);
                        Context.SaveChanges();

                        foreach(var iv in workflowObject.InitAction.InputValueSettingObjects)
                        {
                            iv.InputValueSetting.actionId = workflowObject.InitAction.Action.Id;
                            Context.InputValueSettings.Add(iv.InputValueSetting);
                            Context.SaveChanges();

                            if(iv.Children != null)
                            {
                                foreach(var childIV in iv.Children)
                                {
                                    childIV.actionId = workflowObject.InitAction.Action.Id;
                                    childIV.ParentSettingId = iv.InputValueSetting.Id;
                                    Context.InputValueSettings.Add(childIV);
                                }
                                Context.SaveChanges();
                            }
                        }
                    }
                    else
                    {
                        throw new ApplicationException("没有设定初始化Action！");
                    }

                    workflowObject.Workflow.InitActionId  = workflowObject.InitAction.Action.Id;
                    workflowObject.Workflow.CreateTime = DateTime.Now;
                    workflowObject.Workflow.CreateUserId = Context.Staffs.FirstOrDefault<Staff>(s => s.Name == User.Identity.Name).Id;
                    Context.Workflows.Add(workflowObject.Workflow);

                    
                    Context.SaveChanges();

                    entity.workflowDefine.Step endStep = new entity.workflowDefine.Step() { 
                        Name = "结束", 
                        workflowId = workflowObject.Workflow.Id ,
                    };
                    Context.Steps.Add(endStep);
                    Context.SaveChanges();

                    workflowObject.Workflow.EndStepId = endStep.Id;
                    Context.SaveChanges();

                    t.Commit();
                }
                catch(Exception ex)
                {
                    t.Rollback();
                    ret.Success = false;
                    ret.ErrorMessage = ex.Message;
                }
            }

            return ret;
        }

        public ApiSaveResponse DeleteWorkflow(int workflowId)
        {
            ApiSaveResponse ret = new ApiSaveResponse();
            ret.Success = true;

            using (var t = Context.Database.BeginTransaction())
            {
                try
                {
                    var wInstanes = Context.WorkflowInstances.Where<WorkflowInstance>(w => w.workflowId == workflowId);
                    if(wInstanes.Count() > 0)
                    {
                        ret.Success = false;
                        ret.ErrorMessage = "流程已经使用，删除会影响到已有流程实例数据!";
                        return ret;
                    }
                    else
                    {
                        var wf = Context.Workflows.FirstOrDefault(w=>w.Id == workflowId);
                        if (wf != null)
                        {
                            entity.workflowDefine.Action  initAction = new entity.workflowDefine.Action() { Id = wf.InitActionId};
                            var tfs = GetTrasfers(workflowId);
                            var Actions = GetActions(workflowId);
                            var Steps = GetSteps(workflowId);

                            foreach (var tf in tfs)
                            {
                                Context.TrasferConditions.Remove(tf);
                            }

                            Context.SaveChanges();

                            foreach (var action in Actions)
                            {
                                
                                var ivSettings1 = Context.InputValueSettings.Where<entity.workflowDefine.InputValueSetting>(
                                    s => s.actionId == action.Id).ToList();

                                foreach(var iv in ivSettings1)
                                {
                                    Context.InputValueSettings.Remove(iv);
                                }
                                if (action.Id != wf.InitActionId)
                                {

                                    Context.Actions.Remove(action);
                                }
                                else
                                {
                                    initAction = action;
                                }
                                
                            }
                            Context.SaveChanges();

                            foreach (var step in Steps)
                            {
                                Context.Steps.Remove(step);
                            }
                            Context.SaveChanges();

                            Context.Workflows.Remove(wf);
                            Context.Actions.Remove(initAction);

                            Context.SaveChanges();
                            t.Commit();
                        }
                    }
                }
                catch(Exception ex)
                {
                    t.Rollback();
                    ret.Success = false;
                    ret.ErrorMessage = ex.Message;
                }
            }

            return ret;
        }

        public ApiSaveResponse SaveStep(NewStepObject stepObj)
        {
            var ret = new ApiSaveResponse();
            ret.Success = true;
            
            using (var t = Context.Database.BeginTransaction())
            {
                try
                {
                    var step = stepObj.Step;
                    var wf = GetWorkflow(step.workflowId);

                    if(wf == null)
                    {
                        throw new ApplicationException("步骤所属流程不存在！");
                    }

                    if (step.Id == 0)
                    {
                        Context.Steps.Add(step);
                        Context.SaveChanges();

                        if(stepObj.NewActions != null)
                        {
                            foreach(var ac in stepObj.NewActions)
                            {
                                ac.Action.StepId = step.Id;
                                Context.Actions.Add(ac.Action);
                                Context.SaveChanges();

                                if(ac.NewInputValueSettingObjects!= null)
                                {
                                    foreach(var iv in ac.NewInputValueSettingObjects)
                                    {
                                        iv.InputValueSetting.actionId = ac.Action.Id;
                                        Context.InputValueSettings.Add(iv.InputValueSetting);

                                        Context.SaveChanges();

                                        if(iv.InputValueSetting.valueType == entity.workflowDefine.EnumFieldType.List)
                                        {
                                            if(iv.Children != null)
                                            {
                                                foreach(var cIV in iv.Children)
                                                {
                                                    cIV.ParentSettingId = iv.InputValueSetting.Id;
                                                    Context.InputValueSettings.Add(cIV);
                                                }

                                                Context.SaveChanges();
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                    else
                    {
                        var temStep = Context.Steps.FirstOrDefault(a => a.Id == step.Id);
                        if (temStep != null)
                        {
                            if (temStep.workflowId != step.workflowId)
                            {
                                throw new ApplicationException("修改步骤时，不能修改步骤所属流程！");
                            }

                            temStep.Name = step.Name;
                            temStep.stepType = step.stepType;
                            temStep.defaultResponseSetting = step.defaultResponseSetting;
                            
                            Context.SaveChanges();

                            if (stepObj.NewActions != null)
                            {
                                foreach (var ac in stepObj.NewActions)
                                {
                                    ac.Action.StepId = temStep.Id;
                                    Context.Actions.Add(ac.Action);
                                    Context.SaveChanges();

                                    if (ac.NewInputValueSettingObjects != null)
                                    {
                                        foreach (var iv in ac.NewInputValueSettingObjects)
                                        {
                                            iv.InputValueSetting.actionId = ac.Action.Id;
                                            Context.InputValueSettings.Add(iv.InputValueSetting);
                                            Context.SaveChanges();

                                            if (iv.InputValueSetting.valueType == entity.workflowDefine.EnumFieldType.List)
                                            {
                                                if (iv.Children != null)
                                                {
                                                    foreach (var cIV in iv.Children)
                                                    {
                                                        cIV.ParentSettingId = iv.InputValueSetting.Id;
                                                        Context.InputValueSettings.Add(cIV);
                                                    }

                                                    Context.SaveChanges();
                                                }
                                            }
                                        }
                                    }

                                    Context.SaveChanges();
                                }
                            }

                            if(stepObj.ModifyActions != null)
                            {
                                foreach(var ac in stepObj.ModifyActions)
                                {

                                    var temAction = Context.Actions.FirstOrDefault(a=>a.Id == ac.Action.Id);

                                    if(temAction != null)
                                    {
                                        temAction.Name = ac.Action.Name;
                                        temAction.InputForm = ac.Action.InputForm;
                                        //temAction.inputValuesSettings = ac.Action.inputValuesSettings;
                                        temAction.OnActionObjectType = ac.Action.OnActionObjectType;
                                        Context.SaveChanges();

                                        if(ac.NewInputValueSettingObjects != null)
                                        {
                                            foreach (var iv in ac.NewInputValueSettingObjects)
                                            {
                                                iv.InputValueSetting.actionId = ac.Action.Id;
                                                Context.InputValueSettings.Add(iv.InputValueSetting);

                                                Context.SaveChanges();

                                                if (iv.InputValueSetting.valueType == entity.workflowDefine.EnumFieldType.List)
                                                {
                                                    if (iv.Children != null)
                                                    {
                                                        foreach (var cIV in iv.Children)
                                                        {
                                                            cIV.ParentSettingId = iv.InputValueSetting.Id;
                                                            Context.InputValueSettings.Add(cIV);
                                                        }

                                                        Context.SaveChanges();
                                                    }
                                                }
                                            }
                                            Context.SaveChanges();
                                        }

                                        if(ac.UpdateInputValueSettingObjects != null)
                                        {
                                            foreach (var iv in ac.UpdateInputValueSettingObjects)
                                            {
                                                var temIvObj = Context.InputValueSettings.FirstOrDefault(s=>s.Id == iv.InputValueSetting.Id);

                                                if(temIvObj != null)
                                                {
                                                    temIvObj.actionId = iv.InputValueSetting.actionId;
                                                    temIvObj.bindField = iv.InputValueSetting.bindField;
                                                    temIvObj.bindFieldSavetoObjectCondition = iv.InputValueSetting.bindFieldSavetoObjectCondition;
                                                    temIvObj.DisplayName = iv.InputValueSetting.DisplayName;
                                                    temIvObj.Options = iv.InputValueSetting.Options;

                                                    Context.SaveChanges();
                                                }
                                                
                                            }
                                            Context.SaveChanges();
                                        }
                                    }
                                    
                                }
                            }


                        }
                        else
                        {
                            throw new ApplicationException("Id不存在！");
                        }
                    }

                    Context.SaveChanges();
                    t.Commit();
                }
                catch(Exception ex)
                {
                    t.Rollback();
                    ret.Success = false;
                    ret.ErrorMessage = ex.Message;
                }
            }

            return ret;
        }
        public ApiSaveResponse DeleteAction(int Id)
        {
            ApiSaveResponse ret = new ApiSaveResponse();
            ret.Success = true;

            using (var t = Context.Database.BeginTransaction())
            {
                try
                {
                    var action = Context.Actions.Where<entity.workflowDefine.Action>(w => w.Id == Id).FirstOrDefault();
                    if (action != null)
                    {
                        var ivSettings1 = Context.InputValueSettings.Where<entity.workflowDefine.InputValueSetting>(
                            s => s.actionId == action.Id).ToList();

                        foreach (var iv in ivSettings1)
                        {
                            Context.InputValueSettings.Remove(iv);
                        }

                        Context.Actions.Remove(action);

                        Context.SaveChanges();
                        t.Commit();
                    }
                }
                catch (Exception ex)
                {
                    t.Rollback();
                    ret.Success = false;
                    ret.ErrorMessage = ex.Message;
                }
            }

            return ret;
        }

        
        public ApiSaveResponse DeleteTransfer(int Id)
        {
            ApiSaveResponse ret = new ApiSaveResponse();
            ret.Success = true;

            using (var t = Context.Database.BeginTransaction())
            {
                try
                {
                    Context.TrasferConditions.Remove(new entity.workflowDefine.TrasferCondition() { Id=Id });
                    Context.SaveChanges();
                    t.Commit();
                }
                catch (Exception ex) 
                {
                    t.Rollback();
                    ret.Success = false;
                    ret.ErrorMessage = ex.Message;
                }
            }

            return ret;
        }

        public ApiSaveResponse DeleteInputValueSetting(int Id)
        {
            ApiSaveResponse ret = new ApiSaveResponse();
            ret.Success = true;

            using (var t = Context.Database.BeginTransaction())
            {
                try
                {
                    Context.InputValueSettings.Remove(new entity.workflowDefine.InputValueSetting() { Id = Id });
                    Context.SaveChanges();
                    t.Commit();
                }
                catch (Exception ex)
                {
                    t.Rollback();
                    ret.Success = false;
                    ret.ErrorMessage = ex.Message;
                }
            }

            return ret;
        }

        public ApiSaveResponse DeleteStep(int Id)
        {
            ApiSaveResponse ret = new ApiSaveResponse();
            ret.Success = true;

            using (var t = Context.Database.BeginTransaction())
            {
                try
                {
                    var step = Context.Steps.FirstOrDefault(s=>s.Id == Id);

                    if(step != null)
                    {
                        var Transfers = Context.TrasferConditions.Where<entity.workflowDefine.TrasferCondition>(t => t.StepId == step.Id || t.nextStepId == step.Id).ToList();
                        if(Transfers != null)
                        {
                            foreach(var tf in Transfers)
                            {
                                Context.TrasferConditions.Remove(tf);
                            }

                            Context.SaveChanges();
                        }

                        var Actions = Context.Actions.Where<entity.workflowDefine.Action>(s => s.StepId == step.Id).ToList();

                        if(Actions != null)
                        {
                            foreach(var ac in Actions)
                            {
                                foreach(var iv in Context.InputValueSettings.Where(p=>p.actionId== ac.Id).ToList())
                                {
                                    Context.InputValueSettings.Remove(iv);
                                }
                                

                                Context.Actions.Remove(ac);
                            }

                            Context.SaveChanges();
                        }

                        Context.Steps.Remove(step);
                        Context.SaveChanges();
                    }





                    t.Commit();
                }
                catch (Exception ex)
                {
                    t.Rollback();
                    ret.Success = false;
                    ret.ErrorMessage = ex.Message;
                }
            }

            return ret;
        }

        public ApiSaveResponse SaveAction(entity.workflowDefine.Action action)
        {
            var ret = new ApiSaveResponse();
            ret.Success = true;
            using (var t = Context.Database.BeginTransaction())
            {
                try
                {
                    var temInputValueSettings = action.inputValuesSettings;
                    action.inputValuesSettings = null;

                    if (action.Id == 0)
                    {
                        Context.Actions.Add(action);
                        Context.SaveChanges();

                        if (temInputValueSettings != null)
                        {
                            foreach (var iv in temInputValueSettings)
                            {
                                iv.actionId = action.Id;

                                Context.InputValueSettings.Add(iv);
                            }

                            Context.SaveChanges();
                        }
                    }
                    else
                    {
                        var temAtion = Context.Actions.FirstOrDefault(a => a.Id == action.Id);
                        if (temAtion != null)
                        {
                            temAtion.InputForm = action.InputForm;
                            temAtion.Name = action.Name;
                            temAtion.StepId = action.StepId;
                            temAtion.inputValuesSettings = action.inputValuesSettings;
                            temAtion.OnActionObjectType = action.OnActionObjectType;

                            if(temInputValueSettings != null)
                            {
                                foreach (var iv in temInputValueSettings)
                                {
                                    var temIV = Context.InputValueSettings.FirstOrDefault(p=>p.Id == iv.Id);

                                    if(temIV != null)
                                    {
                                        temIV.actionId = iv.actionId;
                                        temIV.bindField = iv.bindField;
                                        temIV.bindFieldSavetoObjectCondition = iv.bindFieldSavetoObjectCondition;
                                        temIV.DisplayName = iv.DisplayName;
                                        temIV.Options = iv.Options;
                                        temIV.ParentSettingId = iv.ParentSettingId;
                                    }
                                    else
                                    {
                                        iv.actionId = action.Id;
                                        Context.InputValueSettings.Add(iv);
                                    }
                                    

                                    
                                }

                                Context.SaveChanges();
                            }
                        }
                        else
                        {
                            throw new ApplicationException("Id不存在！");
                        }

                    }
                    Context.SaveChanges();

                    t.Commit();
                }
                catch (Exception ex)
                {
                    t.Rollback();
                    ret.Success = false;
                    ret.ErrorMessage = ex.Message;
                }
            }

            return ret;
        }

        public ApiSaveResponse SaveTransfer(entity.workflowDefine.TrasferCondition trasfer)
        {
            var ret = new ApiSaveResponse();
            ret.Success = true;

            using (var t = Context.Database.BeginTransaction())
            {
                try
                {
                    
                    

                    if (trasfer.Id == 0)
                    {
                        Context.TrasferConditions.Add(trasfer);
                    }
                    else
                    {
                        var temTransfer = Context.TrasferConditions.FirstOrDefault(a => a.Id == trasfer.Id);
                        if (temTransfer != null)
                        {
                            temTransfer.StepId  = trasfer.StepId;
                            temTransfer.nextStepId = trasfer.nextStepId;
                            temTransfer.Condition = trasfer.Condition;
                        }
                        else
                        {
                            throw new ApplicationException("Id不存在！");
                        }
                    }

                    Context.SaveChanges();
                    t.Commit();
                }
                catch (Exception ex)
                {
                    t.Rollback();
                    ret.Success = false;
                    ret.ErrorMessage = ex.Message;
                }
            }

            return ret;
        }

        public List<entity.workflowDefine.Workflow> GetAllWorkflows()
        {
            return Context.Workflows.Include(d => d.CreateUser).ToList();
        }

        public entity.workflowDefine.Workflow GetWorkflow(int workflowId)
        {
            return Context.Workflows.Include(d=>d.InitAction).Include(d=>d.CreateUser).FirstOrDefault<entity.workflowDefine.Workflow>(w => w.Id == workflowId);
        }

        public List<entity.workflowDefine.Step> GetSteps(int workflowId)
        {
            return Context.Steps.Where<entity.workflowDefine.Step>(w => w.workflowId  == workflowId).ToList();
        }

        public List<entity.workflowDefine.Action> GetActions(int workflowId)
        {
            var workflow = Context.Workflows.FirstOrDefault<entity.workflowDefine.Workflow>(w => w.Id == workflowId);
            return Context.Actions.Include(s=>s.step).Where<entity.workflowDefine.Action>(d => d.step.workflowId == workflowId || d.Id == workflow.InitActionId).ToList();
        }

        public List<entity.workflowDefine.TrasferCondition> GetTrasfers(int workflowId)
        {
            return Context.TrasferConditions.Where(d => d.Step.workflowId == workflowId || d.nextStep.workflowId == workflowId).ToList();
        }

        public List<entity.workflowDefine.InputValueSetting>  getInputValueSteein(int actionId)
        {
            var retList=  Context.InputValueSettings.Where<entity.workflowDefine.InputValueSetting>(p => p.actionId == actionId).ToList();
            return retList;
        }

        [HttpGet, DisableRequestSizeLimit]
        public async Task<IActionResult> ExportToImage(int workflowId)
        {
            var workflow = GetWorkflow(workflowId);
            var Steps = GetSteps(workflowId);
            var Actions = GetActions(workflowId);
            var Transfers = GetTrasfers(workflowId);

            FlowChartUtility flowChart = new FlowChartUtility();
            flowChart.workflow = workflow;
            flowChart.Steps = Steps;
            flowChart.Transfers = Transfers;

            string strSvg = flowChart.GetSvgString();

            System.Xml.XmlDocument xmdoc = new System.Xml.XmlDocument();
            xmdoc.LoadXml(strSvg);
            Svg.SvgDocument svg = Svg.SvgDocument.Open(xmdoc);
            Bitmap bitmap = svg.Draw();
            MemoryStream mStream = new MemoryStream();
            bitmap.Save(mStream, ImageFormat.Jpeg);
            
            var filename = $"{workflow.Name}.jpg";
            mStream.Position = 0;
            return File(mStream, GetContentType(filename), filename);

            
        }

        private string GetContentType(string path)
        {
            var provider = new FileExtensionContentTypeProvider();
            string contentType;

            if (!provider.TryGetContentType(path, out contentType))
            {
                contentType = "application/octet-stream";
            }

            return contentType;
        }

        public entity.workflowDefine.InputValueSetting  getInputValueSteeingById(int Id)
        {
            return Context.InputValueSettings.FirstOrDefault(s=>s.Id == Id);
        }
    }
}
