package com.reyun.service;

import com.reyun.util.DBUtil;
import com.reyun.util.StringUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.sql.rowset.serial.SerialArray;

import java.math.BigDecimal;
import java.sql.Array;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service("ReportService")
public class ReportService
{

    protected Logger logger = LoggerFactory.getLogger(ReportService.class);

    public Map<String, List> reportBySql(Map<String, String> conditions)
    {
        Map<String, List> result = new HashMap<>();
        logger.debug(conditions.toString());
        try {
            result = query(conditions.get("sql"), conditions.get("key"), conditions.get("appid"));
        }
        catch (SQLException e) {
            logger.error("fail to query sql from presto", e.getMessage());
        }
        return result;
    }

    public boolean execute(String sql) {
        Connection conn = null;
        ResultSet rs = null;
        Statement stmt = null;

        long start = System.currentTimeMillis();
        DBUtil util = DBUtil.newInstance();

        conn = util.getHiveConn();
        long mid = System.currentTimeMillis();
        boolean success = true;
        logger.debug("------------------get connection time is :" + (mid-start) + "------------------------");
        try {
            stmt = conn.createStatement();
            stmt.execute(sql);
        } catch (SQLException e) {
            success = false;
            e.printStackTrace();
        }

        long query = System.currentTimeMillis();
        logger.debug("-------------------query time is:" + (query-mid) + "-----------------------------");


        util.release(rs, stmt, conn);
        return success;
    }

    public Map<String, List> query(String sql, String key, String appid)
            throws SQLException
    {
        Connection conn = DBUtil.newInstance().getPrestoConn();
        ResultSet rs = null;
        Statement stmt = conn.createStatement();

        try {
            stmt.setQueryTimeout(30);
        }
        catch (Exception e) {
            logger.error(e.getMessage(), e);
        }

        System.out.println(sql);

        String[] sqls = sql.split(";");

        try {

            for (int i = 0; i < sqls.length; i++) {
                if (i == sqls.length - 1) {
                    rs = stmt.executeQuery(sqls[i]);
                }
                else {
                    stmt.execute(sqls[i]);
                }
            }
        }
        catch (Exception e) {

            String message = e.getMessage();

            logger.debug("------KUDU_ERROR--------" + message);
        }

        System.out.println(rs==null);

        long query = System.currentTimeMillis();

        Map<String, List> result = new HashMap<>();
        if (rs != null) {
            result = format(rs, key);
        }

        long end = System.currentTimeMillis();
        logger.debug("-----------------------format time is:" + (end - query) + "-----------------------------");

        DBUtil.release(rs, stmt, conn);

        return result;
    }

    public Map<String, List> format(ResultSet rs, String key)
            throws SQLException
    {
        ResultSetMetaData rsmd = rs.getMetaData();
        int cnt = rsmd.getColumnCount();

        Map<String, List> result = new HashMap<>();
        List<String> columnkeys = new ArrayList<>();
        List<Map<String, Object>> vals = new ArrayList<>();
        Map<String, String> keyType = new HashMap<>();

        for (int i = 0; i < cnt; i++) {
            String n = rsmd.getColumnLabel(i + 1);
            keyType.put(n, rsmd.getColumnTypeName(i + 1));
            columnkeys.add(n);
        }

        List<String> keys = new ArrayList<>();
        List<String> keyList = new ArrayList<>();

        if (!StringUtil.isEmpty(key)) {
            keyList = Arrays.asList(key.split(","));
        }

        while (rs.next()) {

            Map<String, Object> map = new HashMap<>();
            for (String k : keyList) {
                String keyvalue = rs.getString(k);
                keys.add(keyvalue);
                map.put(k.toLowerCase(), keyvalue);
            }

            for (String name : columnkeys) {
                if (rs.getObject(name) != null) {

                    if (name.toLowerCase().endsWith("_rate") || name.toLowerCase().startsWith("rate_") || name.toLowerCase().startsWith("amt_")) {

                        Double rate = rs.getDouble(name);

                        if (!name.toLowerCase().startsWith("amt_") && !name.toLowerCase().startsWith("rate_retentiond") && rate > 100D) {
                            rate = new Double(100);
                        }

                        BigDecimal b = BigDecimal.valueOf(rate);
                        map.put(name.toLowerCase(), b.setScale(2, BigDecimal.ROUND_HALF_UP));
                    }
                    else {

                        if ("ARRAY(BIGINT)".equals(keyType.get(name.toLowerCase())) || "ARRAY(varchar)".equals(keyType.get(name.toLowerCase()))) {
                            Array array = rs.getArray(name);
                            SerialArray jsonArray = new SerialArray(array);
                            map.put(name.toLowerCase(), jsonArray.getArray());
                        }
                        else {
                            map.put(name.toLowerCase(), rs.getObject(name));
                        }
                    }

                    if (!"0".equals(rs.getObject(name).toString())) {
                        map.put("isall0", false);
                    }
                }
                else {
                    if (rs.getObject(name) instanceof String) {

                        map.put(name.toLowerCase(), "unknown");
                    }
                    else if (name.toLowerCase().endsWith("_rate") || name.toLowerCase().startsWith("rate_") || name.toLowerCase().startsWith("amt_")) {

                        map.put(name.toLowerCase(), 0.0);
                    }
                    else {

                        map.put(name.toLowerCase(), 0);
                    }
                }
            }
            vals.add(map);
        }

        result.put("key", keys);
        result.put("val", vals);

        return result;
    }
}
