using DapperExtensions.Lambda;
using DapperExtensions.ValueObject;
using Mall.DataAccess;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DapperExtensions.Sql
{
    /// <summary>
    /// Sql语句配置接口
    /// </summary>
    public interface ISqlDialect
    {
        /// <summary>
        /// 数据库类型枚举
        /// </summary>
        DataBaseType DBType { get; }

        /// <summary>
        /// 开始字符
        /// </summary>
        char OpenQuote { get; }

        /// <summary>
        /// 结束字符
        /// </summary>
        char CloseQuote { get; }

        /// <summary>
        /// 批处理分隔符
        /// </summary>
        string BatchSeperator { get; }

        /// <summary>
        /// 是否支持多项结构
        /// </summary>
        bool SupportsMultipleStatements { get; }
        
        /// <summary>
        /// 参数开始字符
        /// </summary>
        char ParameterPrefix { get; }

        /// <summary>
        /// 空表达式
        /// </summary>
        string EmptyExpression { get; }
        
        /// <summary>
        /// 获取表名
        /// </summary>
        /// <param name="schemaName">架构名称</param>
        /// <param name="tableName">表名</param>
        /// <param name="alias">别名</param>
        /// <param name="dbName">数据库名称</param>
        /// <returns></returns>
        string GetTableName(string schemaName, string tableName, string alias, string dbName = "");

        /// <summary>
        /// 获取列名
        /// </summary>
        /// <param name="prefix">前缀[比如:a.Name]</param>
        /// <param name="columnName">列名</param>
        /// <param name="alias">别名</param>
        /// <returns></returns>
        string GetColumnName(string prefix, string columnName, string alias);

        /// <summary>
        /// 获取自增Sql
        /// </summary>
        /// <param name="tableName">表名</param>
        /// <returns></returns>
        string GetIdentitySql(string tableName);

        /// <summary>
        /// 获取分页Sql
        /// </summary>
        /// <param name="sql">SQL命令</param>
        /// <param name="page">页码</param>
        /// <param name="resultsPerPage">页大小</param>
        /// <param name="parameters">参数</param>
        /// <returns></returns>
        string GetPagingSql(string sql, int page, int resultsPerPage, IDictionary<string, object> parameters);

        /// <summary>
        /// 获取分页SQL
        /// </summary>
        /// <param name="sql">SQL命令</param>
        /// <param name="firstResult">开始值</param>
        /// <param name="maxResults">最大值/结束值</param>
        /// <param name="parameters">参数</param>
        /// <returns></returns>
        string GetSetSql(string sql, int firstResult, int maxResults, IDictionary<string, object> parameters);

        /// <summary>
        /// 是否使用开始和结束字符[比如“[Id]”]
        /// </summary>
        /// <param name="value">值[字段名、表名等]</param>
        /// <returns></returns>
        bool IsQuoted(string value);

        /// <summary>
        /// 格式化字符[比如“[Id]”]
        /// </summary>
        /// <param name="value">值[字段名、表名等]</param>
        /// <returns></returns>
        string QuoteString(string value);

        /// <summary>
        /// 获取前几行Sql
        /// </summary>
        /// <param name="pageIndex">页码</param>
        /// <param name="pageSize">页大小</param>
        /// <returns></returns>
        string GetTopString(int pageIndex, int pageSize);

        
        /// <summary>
        /// 获取表连接
        /// </summary>
        /// <param name="joinType">表连接对象</param>
        /// <returns></returns>
        string GetJoinString(JoinType joinType);

    }

    /// <summary>
    /// Sql语句配置实现基类
    /// </summary>
    public abstract class SqlDialectBase : ISqlDialect
    {
        /// <summary>
        /// 数据库类型
        /// </summary>
        public DataBaseType DBType { get; protected set; }

        /// <summary>
        /// 开始字符
        /// </summary>
        public virtual char OpenQuote
        {
            get { return '"'; }
        }

        /// <summary>
        /// 结束字符
        /// </summary>
        public virtual char CloseQuote
        {
            get { return '"'; }
        }

        /// <summary>
        /// 批处理分隔符
        /// </summary>
        public virtual string BatchSeperator
        {
            get { return ";" + Environment.NewLine; }
        }

        /// <summary>
        /// 是否支持多项结构
        /// </summary>
        public virtual bool SupportsMultipleStatements
        {
            get { return true; }
        }

        /// <summary>
        /// 参数前缀
        /// </summary>
        public virtual char ParameterPrefix
        {
            get
            {
                return '@';
            }
        }

        /// <summary>
        /// 空表达式
        /// </summary>
        public string EmptyExpression
        {
            get
            {
                return "1=1";
            }
        }

        /// <summary>
        /// 获取表名
        /// </summary>
        /// <param name="schemaName">架构名(.dbo)</param>
        /// <param name="tableName">表名</param>
        /// <param name="alias">别名</param>
        /// <param name="dbName">数据库名称</param>
        /// <returns></returns>
        public virtual string GetTableName(string schemaName, string tableName, string alias, string dbName = "")
        {
            if (string.IsNullOrWhiteSpace(tableName))
            {
                throw new ArgumentNullException("TableName", "tableName cannot be null or empty.");
            }
            StringBuilder result = new StringBuilder();
            if (!string.IsNullOrWhiteSpace(schemaName))
            {
                if (!string.IsNullOrWhiteSpace(dbName))
                {
                    result.AppendFormat(QuoteString(dbName) + ".");
                }
                result.AppendFormat(QuoteString(schemaName) + ".");
            }
            result.AppendFormat(QuoteString(tableName));

            if (!string.IsNullOrWhiteSpace(alias))
            {
                result.AppendFormat(" AS {0}", QuoteString(alias));
            }
            return result.ToString();
        }

        /// <summary>
        /// 获取字段名称
        /// </summary>
        /// <param name="prefix">前缀</param>
        /// <param name="columnName">字段名称</param>
        /// <param name="alias">别名</param>
        /// <returns></returns>
        public virtual string GetColumnName(string prefix, string columnName, string alias)
        {
            if (string.IsNullOrWhiteSpace(columnName))
            {
                throw new ArgumentNullException("ColumnName", "columnName cannot be null or empty.");
            }
            StringBuilder result = new StringBuilder();
            if (!string.IsNullOrWhiteSpace(prefix))
            {
                result.AppendFormat(QuoteString(prefix) + ".");
            }
            if (columnName != "*")
            {
                result.AppendFormat(QuoteString(columnName));
            }
            else
            {
                result.AppendFormat(columnName);
            }
            if (!string.IsNullOrWhiteSpace(alias))
            {
                result.AppendFormat(" AS {0}", QuoteString(alias));
            }
            return result.ToString();
        }

        /// <summary>
        /// 获取自增Sql
        /// </summary>
        /// <param name="tableName">表名</param>
        /// <returns></returns>
        public abstract string GetIdentitySql(string tableName);

        /// <summary>
        /// 获取分页的Sql
        /// </summary>
        /// <param name="sql">sql命令</param>
        /// <param name="page">页码</param>
        /// <param name="resultsPerPage"></param>
        /// <param name="parameters">参数字典</param>
        /// <returns></returns>
        public abstract string GetPagingSql(string sql, int page, int resultsPerPage, IDictionary<string, object> parameters);

        /// <summary>
        /// 设置Sql
        /// </summary>
        /// <param name="sql">sql命令</param>
        /// <param name="firstResult">第一结果</param>
        /// <param name="maxResults">最大结果</param>
        /// <param name="parameters">参数</param>
        /// <returns></returns>
        public abstract string GetSetSql(string sql, int firstResult, int maxResults, IDictionary<string, object> parameters);

        /// <summary>
        /// 是否使用开始字符和结束字符[比如“[Id]”]
        /// </summary>
        /// <param name="value">值[字段名、表名等]</param>
        /// <returns></returns>
        public virtual bool IsQuoted(string value)
        {
            if (value.Trim()[0] == OpenQuote)
            {
                return value.Trim().Last() == CloseQuote;
            }
            return false;
        }

        /// <summary>
        /// 格式化字符[比如“[Id]”]
        /// </summary>
        /// <param name="value">值[字段名、表名等]</param>
        /// <returns></returns>
        public virtual string QuoteString(string value)
        {
            return IsQuoted(value) ? value : string.Format("{0}{1}{2}", OpenQuote, value.Trim(), CloseQuote);
        }

        /// <summary>
        /// 获取连接字符串
        /// </summary>
        /// <param name="joinType">表连接类型枚举</param>
        /// <returns></returns>
        public string GetJoinString(JoinType joinType)
        {
            string joinString = string.Empty;
            switch (joinType)
            {
                case JoinType.InnerJoin:
                    joinString = "INNER JOIN";
                    break;
                case JoinType.LeftJoin:
                    joinString = "LEFT JOIN";
                    break;
                case JoinType.RightJoin:
                    joinString = "RIGHT JOIN";
                    break;
                case JoinType.CrossJoin:
                    joinString = "CROSS JOIN";
                    break;
                case JoinType.FullJoin:
                    joinString = "FULL JOIN";
                    break;
                default:
                    joinString = "INNER JOIN";
                    break;
            }
            return joinString;
        }

        /// <summary>
        /// 获取Top的字符串
        /// </summary>
        /// <param name="pageIndex">页码</param>
        /// <param name="pageSize">页大小</param>
        /// <returns></returns>
        public virtual string GetTopString(int pageIndex, int pageSize)
        {
            return string.Empty;
        }
    }
}