using InABox.Core;
using InABox.Scripting;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace InABox.Poster.Custom
{
    public class CustomPosterEngine<TPostable> : PosterEngine<TPostable, ICustomPoster<TPostable>, CustomPosterSettings>
        where TPostable : Entity, IPostable, IRemotable, IPersistent, new()
    {
        private ScriptDocument? _script;
        private bool _hasCheckedScript;

        private ScriptDocument? GetScriptDocument()
        {
            if (_hasCheckedScript)
            {
                return _script;
            }

            var settings = GetSettings();
            if (settings.ScriptEnabled && !string.IsNullOrWhiteSpace(settings.Script))
            {
                var document = new ScriptDocument(settings.Script);
                if (!document.Compile())
                {
                    throw new Exception("Script failed to compile!");
                }
                _script = document;
            }
            else
            {
                _script = null;
            }

            _hasCheckedScript = true;
            return _script;
        }

        public override bool BeforePost(IDataModel<TPostable> model)
        {
            if (GetScriptDocument() is ScriptDocument script)
            {
                return script.Execute(methodname: "BeforePost", parameters: new object[] { model });
            }
            return false;
        }

        protected override IPostResult<TPostable> DoProcess(IDataModel<TPostable> model)
        {
            if (GetScriptDocument() is ScriptDocument script)
            {
                if(!script.Execute(methodname: "Process", parameters: new object[] { model }))
                {
                    throw new Exception("Post Failed.");
                }

                var resultsObject = script.GetValue("Results");
                return (resultsObject as IPostResult<TPostable>)
                    ?? throw new Exception($"Script 'Results' property expected to be IPostResult<{typeof(TPostable)}>, got {resultsObject}");
            }
            else
            {
                throw new Exception("Post Failed.");
            }
        }
        public override void AfterPost(IDataModel<TPostable> model, IPostResult<TPostable> result)
        {
            if (GetScriptDocument() is ScriptDocument script)
            {
                script.Execute(methodname: "AfterPost", parameters: new object[] { model });
            }
        }
    }
}
