package com.org.hktshop.utils;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import com.org.hktshop.base.BaseException;
import com.org.hktshop.target01.TableField;
import com.org.hktshop.target01.TableName;

/***
 * SQL生成工具
 * @author mxk
 *
 */
public class ExecSqlLib {
    public static final int SplitCount = 1000;

    /***
     * 执行插入语句。每条记录进行分拆 返回list
     *
     * @param record
     * @return
     * @throws Exception
     */
    public static List<String> GetInsertSqlCount(List< ?> record) {
        int perLength = SplitCount; // 超过多少行拆分值
        if (perLength < 0)
            perLength = 1;
        int ListSzie = record.size();
        List<String> OutSql = new ArrayList<>();
        while (true) {
            int EndSzie = ListSzie;
            int StartSize = ListSzie - perLength;
            if (StartSize < 0) {
                StartSize = 0;
                List<?> list = record.subList(StartSize, EndSzie);
                OutSql.add(GetInsertSql(list));
                break;
            } else {
                ListSzie -= perLength;
                List<?> list = record.subList(StartSize, EndSzie);
                OutSql.add(GetInsertSql(list));
                if (ListSzie <= 0)
                    break;
            }
        }
        return OutSql;
    }

    /**
     * 生成交返回一条记录的Sql语句
     *
     * @param record
     * @return
     * @throws Exception
     */
    public static String GetInsertSql(Object record) {
        List<Object> newrecord = new ArrayList<>();
        newrecord.add(record);
        return GetInsertSql(newrecord);
    }

    /***
     * 根据实体返回 映射的表
     * @param record
     * @return
     */
    public static String getTableName(Object record) {
        TableName table = record.getClass().getAnnotation(TableName.class);
        String name = table.value();
        if (name == null || "".equals(name)) {
            throw new BaseException(record.getClass().getName() + " table name is not found");
        }

        return name;
    }

    /***
     * 根據MAP獲取條數
     * @param params
     * @return
     */
    public static String GetCountSql(Object record, Map<String, Object> params) {
        String TableName = getTableName(record);
        List<String> outValues = new ArrayList<>();
        for (Entry<String, Object> in_entry : params.entrySet()) {
            String val = in_entry.getKey() + " = " + in_entry.getValue();
            outValues.add(val);
        }

        String sql = String.format("select count(1) as count from  %s %s %s", TableName, " where ", String.join(" and ", outValues));

        return sql;
    }

    /***
     * 根據實體對象獲取表行數
     * @param record
     * @return
     */
    public static String GetCountSql(Object record) {
        String TableName = getTableName(record);
        String sql = "select count(1) as count from " + TableName;

        List<String> OutValues = new ArrayList<>();

        Class<?> clazz = record.getClass();
        List<Field> MyFiles = ClassUtils.getSelfBeanInfo(clazz);
        //获取查询字段
        for (Field fd : MyFiles) {
            TableField annotation = fd.getAnnotation(TableField.class);
            if (annotation == null) continue;

            Object Filename = annotation.value();
            if ("".equals(Filename)) continue;

            Object Value = null;
            try {
                Method m = (Method) clazz.getMethod(
                        "get" + getMethodName(fd.getName()));
                Value = m.invoke(record);// 调用getter方法获取属性值
            } catch (Exception e) {
                e.printStackTrace();
            }
            if (StringUtils.isNull(Value)) continue;

            // 判断是否为字符串类型
            if (fd.getType().equals(String.class)) {
                OutValues.add(Filename + " = '" + Value + "'");
            } else if (fd.getType().equals(Date.class)) {
                // 判断是否为日期
                OutValues.add(Filename + " = '" + DateUtil.formatTime(Value) + "'");
            } else {
                OutValues.add(Filename + " = " + Value + "");
            }

        }

        String SqlWhere = String.format(" where %s ", String.join(" and ", OutValues));
        sql = sql + SqlWhere;

        return sql;
    }

    /***
     * 根據sql获取行数
     * @return
     */
    public static String GetCountSql(String in_sql) {
        String sql = "select count(1) as count from (" + in_sql + ") t";
        return sql;
    }

    /***
     * 根据ID删除 实体对应表数据
     * @param id
     * @param record
     * @return
     */
    public static String GetDeleteByIdSql(String id, Object record) {
        String TableName = getTableName(record);
        String sql = String.format("delete from %s %s '%s'", TableName, " where id = ", id);
        return sql;
    }

    /***
     * 獲取對象對應字段
     * @param record
     * @return
     */
    public static String getSelectFileds(Object record) {
        Class<?> clazz = record.getClass();
        List<String> OutValues = new ArrayList<>();
        List<Field> MyFiles = ClassUtils.getSelfBeanInfo(clazz);
        for (Field fd : MyFiles) {
            TableField annotation = fd.getAnnotation(TableField.class);
            if (annotation == null) continue;

            String Filename = annotation.value();
            if (!annotation.exist()) continue;
            OutValues.add(Filename + " as " + StringUtils.underline2Camel(Filename, true));
        }
        return String.join(",", OutValues);
    }

    /***
     * 根據實體刪除  params 自定義條件
     * @param record
     * @returnparams
     */
    public static String GetDeleteSqlByParams(Object record, Map<String, Object> params) {
        String TableName = getTableName(record);

        List<String> outValues = new ArrayList<>();
        for (Entry<String, Object> in_entry : params.entrySet()) {
            String val = in_entry.getKey() + " = " + in_entry.getValue();
            outValues.add(val);
        }
        String sql = String.format("delete from %s %s %s", TableName, " where ", String.join(" and ", outValues));
        return sql;
    }

    /***
     * 根據實體刪除
     * @param record
     * @return
     */
    public static String GetDeleteSql(Object record) {
        String TableName = getTableName(record);
        Class<?> clazz = record.getClass();

        List<String> OutValues = new ArrayList<>();
        List<Field> MyFiles = ClassUtils.getSelfBeanInfo(clazz);
        for (Field fd : MyFiles) {
            TableField annotation = fd.getAnnotation(TableField.class);
            if (annotation == null) continue;

            String Filename = annotation.value();

            Object Value = null;
            try {
                Method m = (Method) clazz.getMethod(
                        "get" + getMethodName(fd.getName()));
                Value = m.invoke(record);// 调用getter方法获取属性值
            } catch (Exception e) {
                e.printStackTrace();
            }

            if (Value == null || "".equals(Value)) continue;
            if (!annotation.exist()) continue;

            // 判断是否为字符串类型
            if (fd.getType().equals(String.class)) {
                OutValues.add(Filename + " = '" + Value + "'");
            } else if (fd.getType().equals(Date.class)) {
                // 判断是否为日期
                OutValues.add(Filename + " = '" + DateUtil.formatTime(Value) + "'");
            } else {
                OutValues.add(Filename + " = " + Value + "");
            }

        }
        if (OutValues.isEmpty()) {
            throw new BaseException(clazz.getName() + " where is Empty!");
        }
        String sql = String.format("delete from %s %s %s", TableName, " where ", String.join(" and ", OutValues));
        return sql;
    }

    /**
     * 根据实体返回一条更新语句
     * where id = ?
     *
     * @param record
     * @return
     * @throws Exception
     */
    public static String GetUpdateSql(Object record) {
        List<Object> newrecord = new ArrayList<>();
        newrecord.add(record);
        return GetUpdateSqlById(newrecord).get(0);
    }

    /**
     * 根据实体返回一条更新语句
     * where 自定义条件
     *
     * @param record 实体对象
     * @param params 条件属性
     * @return
     * @throws Exception
     */
    public static String GetUpdateSql(Object record, List<String> params) {
        List<Object> newrecord = new ArrayList<>();
        newrecord.add(record);
        return GetUpdateSqlById(newrecord, params).get(0);
    }

    /***
     * 根据实体返回更新语句
     * where 自定义条件
     * @param record 更新数据
     * @param params 条件属性
     * @return
     */
    public static List<String> GetUpdateSqlById(List<?> record, List<String> params) {
        if (record.size() < 1)
            return new ArrayList<String>();

        List<String> listSql = new ArrayList<String>();

        Class<?> clazz = record.get(0).getClass();
        String TableName = getTableName(record.get(0));

        List<Field> MyFiles = ClassUtils.getSelfBeanInfo(clazz);

        for (Object re : record) {
            List<String> OutValues = new ArrayList<>();
            List<String> whereVaules = new ArrayList<>();
            for (Field fd : MyFiles) {
                TableField annotation = fd.getAnnotation(TableField.class);
                if (annotation == null) continue;

                String Filename = annotation.value();

                Object Value = null;
                try {
                    Method m = (Method) clazz.getMethod(
                            "get" + getMethodName(fd.getName()));
                    Value = m.invoke(re);// 调用getter方法获取属性值
                } catch (Exception e) {
                    e.printStackTrace();
                }

                if (Value == null || "".equals(Value)) continue;
                if (!annotation.exist()) continue;
                if ("id".equals(Filename)) {
                    //ID 不作為更新數據
                    continue;
                }

                boolean isWhere = false;
                if (params.contains(fd.getName())) {
                    isWhere = true;
                }

                // 判断是否为字符串类型
                String val = Filename + " = " + Value + "";

                if (fd.getType().equals(String.class)) {
                    val = Filename + " = '" + Value + "'";
                } else if (fd.getType().equals(Date.class)) {
                    // 判断是否为日期
                    val = Filename + " = '" + DateUtil.formatTime(Value) + "'";
                }
                OutValues.add(val);
                //构建where
                if (isWhere) {
                    whereVaules.add(Filename + " = '" + Value + "'");
                }
            }

            if (whereVaules.isEmpty()) {
                throw new BaseException(clazz.getName() + " where Condition is empty.");
            }

            String SqlFirstStr = String.format("update %s %s %s", TableName, " set ", String.join(",", OutValues));
            SqlFirstStr += String.format(" where %s", String.join(" and ", whereVaules));

            listSql.add(SqlFirstStr);
        }
        return listSql;
    }

    /***
     * 根据实体返回更新语句 KEY = ID
     * @param record
     * @return
     */
    public static List<String> GetUpdateSqlById(List<?> record) {
        if (record.size() < 1)
            return new ArrayList<String>();

        List<String> listSql = new ArrayList<String>();

        Class<?> clazz = record.get(0).getClass();
        String TableName = getTableName(record.get(0));

        List<Field> MyFiles = ClassUtils.getSelfBeanInfo(clazz);

        for (Object re : record) {
            Object primaryValue = null;
            List<String> OutValues = new ArrayList<>();
            for (Field fd : MyFiles) {
                TableField annotation = fd.getAnnotation(TableField.class);
                if (annotation == null) continue;

                String Filename = annotation.value();

                Object Value = null;
                try {
                    Method m = (Method) clazz.getMethod(
                            "get" + getMethodName(fd.getName()));
                    Value = m.invoke(re);// 调用getter方法获取属性值
                } catch (Exception e) {
                    e.printStackTrace();
                }

                if (Value == null || "".equals(Value)) continue;
                if (!annotation.exist()) continue;
                if ("id".equals(Filename)) {
                    //ID 不作為更新數據
                    primaryValue = Value;
                    continue;
                }

                // 判断是否为字符串类型
                if (fd.getType().equals(String.class)) {
                    OutValues.add(Filename + " = '" + Value + "'");
                } else if (fd.getType().equals(Date.class)) {
                    // 判断是否为日期
                    OutValues.add(Filename + " = '" + DateUtil.formatTime(Value) + "'");
                } else {
                    OutValues.add(Filename + " = " + Value + "");
                }

            }

            if (primaryValue == null || "".equals(primaryValue)) {
                throw new BaseException(clazz.getName() + " id is null!");
            }

            String SqlFirstStr = String.format("update %s %s %s", TableName, " set ", String.join(",", OutValues));
            SqlFirstStr += " where id = '" + primaryValue + "'";

            listSql.add(SqlFirstStr);
        }
        return listSql;
    }

    /***
     * 根据實體获取单表查询
     * @param record    表对应的实体
     * @return
     */
    public static String GetQuerySql(Map<String, Object> params, Object record) {
        String TableName = getTableName(record);

        List<String> OutValues = new ArrayList<>();
        List<String> columns = new ArrayList<>();

        Class<?> clazz = record.getClass();
        List<Field> MyFiles = ClassUtils.getSelfBeanInfo(clazz);
        //获取查询字段
        for (Field fd : MyFiles) {
            TableField annotation = fd.getAnnotation(TableField.class);
            if (annotation == null) continue;

            Object Value = annotation.value();

            if ("".equals(Value)) continue;
            if (!annotation.exist()) continue;
            /***
             * 获取 where 条件
             */
            Object p = params.get(Value);
            boolean isString = false;
            if (fd.getType().equals(String.class) || fd.getType().equals(Date.class)) {
                isString = true;
            }
            if (!StringUtils.isNull(p)) {
                if (isString) OutValues.add(Value + " = '" + p + "'");

                else OutValues.add(Value + " = " + p);
            }

            columns.add(Value + " as " + StringUtils.underline2Camel(Value, true));
        }

        String sql = String.format("select %s %s %s", String.join(",", columns), "from", TableName);
        sql += String.format(" where %s", String.join(" and ", OutValues));//暫時以ID排序

        //自定義排序
        Object orderBy = null;
        if (params.containsKey("orderBy")) {
            orderBy = params.get("orderBy");
        }
        if (!StringUtils.isNull(orderBy)) {
            sql += " order by " + orderBy;
        } else {
            sql += " order by id ";
        }

        return sql;
    }

    /****
     * 获取结构查询的所有实体，不封装sql 需后面处理
     * 为特殊查询使用 比如in 方法
     * @param record
     * @return
     */
    public static String GetQueryItmesSql(Object record) {
        String TableName = getTableName(record);

        List<String> columns = new ArrayList<>();
        Class<?> clazz = record.getClass();
        List<Field> MyFiles = ClassUtils.getSelfBeanInfo(clazz);
        //获取查询字段
        for (Field fd : MyFiles) {
            TableField annotation = fd.getAnnotation(TableField.class);
            if (annotation == null) continue;

            Object Value = annotation.value();
            if ("".equals(Value)) continue;
            columns.add(Value + " as " + StringUtils.underline2Camel(Value, true));
        }
        String sql = String.format("select %s %s %s", String.join(",", columns), "from", TableName);

        return sql;
    }


    /***
     * 根据MAP获取单表查询
     * @param record    表对应的实体
     * @return
     */
    public static String GetQuerySql(Object record) {
        String TableName = getTableName(record);

        List<String> OutValues = new ArrayList<>();
        List<String> columns = new ArrayList<>();

        Class<?> clazz = record.getClass();
        List<Field> MyFiles = ClassUtils.getSelfBeanInfo(clazz);
        //获取查询字段
        for (Field fd : MyFiles) {
            TableField annotation = fd.getAnnotation(TableField.class);
            if (annotation == null) continue;

            Object Value = annotation.value();

            if ("".equals(Value)) continue;

            Object p = null;
            try {
                Method m = (Method) clazz.getMethod(
                        "get" + getMethodName(fd.getName()));
                p = m.invoke(record);// 调用getter方法获取属性值
            } catch (Exception e) {
                e.printStackTrace();
            }

            boolean isString = false;
            if (fd.getType().equals(String.class) || fd.getType().equals(Date.class)) {
                isString = true;
            }
            if (!StringUtils.isNull(p)) {
                if (isString) OutValues.add(Value + " = '" + p + "'");
                else OutValues.add(Value + " = " + p);
            }

            columns.add(Value + " as " + StringUtils.underline2Camel(Value, true));
        }

        String sql = String.format("select %s %s %s", String.join(",", columns), "from", TableName);
        if (!OutValues.isEmpty()) {
            sql += String.format(" where %s", String.join(" and ", OutValues));//暫時以ID排序
        }

        //自定義排序
//		Object orderBy = null;
//		try {
//			Method m = (Method) record.getClass().getMethod("getOrderBy");  
//			orderBy = m.invoke(record);// 调用getter方法获取属性值  
//		} catch (Exception e) {
//			e.printStackTrace();
//		}
//		if(!StringUtils.isNull(orderBy)){
//			sql +=  " order by " + orderBy;
//		}else{
        sql += " order by id ";
//		}

        return sql;
    }

    /***
     * 获取批量插入的sql
     * @param record
     * @return
     */
    private static String GetInsertSql(List<?> record) {
        if (record.size() < 1)
            return "";

        boolean GetTile = true;
        List<String> fields = new ArrayList<>();
        List<String> OutOneValue = new ArrayList<>();

        Class<?> clazz = record.get(0).getClass();
        String TableName = getTableName(record.get(0));

        List<Field> MyFiles = ClassUtils.getSelfBeanInfo(clazz);
        for (Object re : record) {
            List<String> OutValues = new ArrayList<>();
            for (Field fd : MyFiles) {
                TableField annotation = fd.getAnnotation(TableField.class);
                if (annotation == null) continue;

                String Filename = annotation.value();
                if ("".equals(Filename)) continue;

                Object Value = null;
                try {
                    Method m = (Method) clazz.getMethod(
                            "get" + getMethodName(fd.getName()));
                    Value = m.invoke(re);// 调用getter方法获取属性值
                } catch (Exception e) {
                    e.printStackTrace();
                }
//				if("id".equals(Filename)) {
//					if(StringUtils.isNull(Value)) Value = IdWorker.nextId(); //TODO  需优化
//				}

                if (Value == null || "".equals(Value)) continue;


                if (GetTile)
                    fields.add(Filename);

                // 判断是否为字符串类型
                if (fd.getType().equals(String.class)) {
                    OutValues.add("'" + Value + "'");
                } else if (fd.getType().equals(Date.class)) {
                    // 判断是否为日期
                    OutValues.add("'" + DateUtil.formatTime(Value) + "'");
                } else {
                    OutValues.add("" + Value + "");
                }
            }
            String TempSql = String.format("(%s)", String.join(",", OutValues));
            OutOneValue.add(TempSql);

            GetTile = false;
        }

        String SqlFirstStr = String.format("insert into %s (%s)", TableName, String.join(",", fields));
        return String.format("%s values %s", SqlFirstStr, String.join(",", OutOneValue));
    }

    //反射为属性方法 获取value
    private static String getMethodName(String fildeName) throws Exception {
        byte[] items = fildeName.getBytes();
        items[0] = (byte) ((char) items[0] - 'a' + 'A');
        return new String(items);
    }

    /***
     * 根据KSN删除 实体对应表数据
     * @param id
     * @param record
     * @return
     */
    public static String GetDeleteByKsnSql(String id, Object record) {
        String TableName = getTableName(record);
        String sql = String.format("delete from %s %s '%s'", TableName, " where goods_id = ", id);
        return sql;
    }
}
