﻿using System;
using System.Data;
using Codeo.Data.Orm.Contract;
using Codeo.Data.Orm.Factory;
using Codeo.Data.Orm.Impl;
using Codeo.Log.Contract.Appender;
using Codeo.Log.Enumeration;
using Codeo.Log.Impl.Configuration;
using Codeo.Log.Entity;
using Ninject;

namespace Codeo.Log.Impl.Appender
{
    public class DbAppender : LogAppenderBase, ILogAppender
    {
        [Inject]
        private readonly IDataContext _dataContext;
        [Inject]
        private readonly IStatementBuilderFactory _statementBuilderFactory;

        private readonly string targetConnectionString;
        private readonly string targetTable;
        private readonly string targetDateColumn;
        private readonly string targetLevelColumn;
        private readonly string targetDataColumn;
        private readonly string targetTagColumn;
        private readonly string targetMemberNameColumn;
        private readonly string targetFilePathColumn;
        private readonly string targetLineNumberColumn;


        public DbAppender(AppenderConfiguration configuration)
            : base(configuration)
        {
            targetConnectionString = configuration.Parameters.ConnectionString;
            targetTable = configuration.Parameters.Table;
            targetDateColumn = configuration.Parameters.DateColumn;
            targetLevelColumn = configuration.Parameters.LevelColumn;
            targetDataColumn = configuration.Parameters.DataColumn;
            targetTagColumn = configuration.Parameters.TagColumn;
            targetMemberNameColumn = configuration.Parameters.MemberNameColumn;
            targetFilePathColumn = configuration.Parameters.FilePathColumn;
            targetLineNumberColumn = configuration.Parameters.LineNumberColumn;
        }

        public void Log(ELogLevel level, string value, string tags=null, string memberName = null, string filePath = null, int lineNumber = 0)
        {
            if (_enabledLevel <= level)
            {
                LogEntry message = LogEntry.Create(level, tags, value, memberName, filePath, lineNumber);
                InsertLog(message.Date, message.Level, message.Data, message.Tags);
            }
        }

        public void SetTitle(string pTitle)
        {
            _title = pTitle;
        }

        private void InsertLog(DateTime date, ELogLevel level, string data,string tag, string memberName = null, string filePath = null, int lineNumber = 0)
        {

			IDataContext c = _dataContext;
            IStatementBuilder statement = null;
            try
            {
                BuildInsertQuery(ref statement, date, level, data, tag,memberName,filePath,lineNumber);
                statement = _statementBuilderFactory.Build(QueryType.Insert);
                c.Execute(statement);
            }
            catch (Exception e)
            {
                throw new Exception(
                    $"[DAL] Query:\"{statement?.ToString() ?? ""}\" Error:\"{e.Message}\" StatckTrace:\"{e.StackTrace}\"");
            }
        }

        private void BuildInsertQuery(ref IStatementBuilder pStatement, DateTime date, ELogLevel level, string data,string tag,string memberName = null, string filePath = null, int lineNumber = 0)
        {
            pStatement.Append($"insert into {targetTable}({targetDateColumn},{targetLevelColumn},{targetDataColumn},{targetTagColumn},{targetMemberNameColumn},{targetFilePathColumn},{targetLineNumberColumn})");
            pStatement.Append($"values(@{targetDateColumn},@{targetLevelColumn},@{targetDataColumn},@{targetTagColumn},@{targetMemberNameColumn},@{targetFilePathColumn},@{targetLineNumberColumn})");
            pStatement.AddParameter(targetDateColumn, date, DbType.DateTime);
            pStatement.AddParameter(targetLevelColumn, level, DbType.String);
            pStatement.AddParameter(targetDataColumn, data, DbType.String);
            pStatement.AddParameter(targetTagColumn, tag, DbType.String);
            pStatement.AddParameter(targetMemberNameColumn, memberName, DbType.String);
            pStatement.AddParameter(targetFilePathColumn, filePath, DbType.String);
            pStatement.AddParameter(targetLineNumberColumn, lineNumber, DbType.Int32);
        }

    }
}
