package com.cisdi.data.DIClient.gateway;

import com.cisdi.data.DIClient.bean.PDIOVo;
import com.cisdi.data.common.exception.BusinessException;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.sql.*;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Date;

public class DBReader
{
    Logger logger= LoggerFactory.getLogger(DBReader.class);

    /**
     * JDBC的连接对象实例
     */
    private Connection conn = null;
    private String driver;
    private String url;
    private String username;
    private String password;

    public DBReader(String driver, String url, String username, String password) {
        this.driver = driver;
        this.url = url;
        this.username = username;
        this.password = password;
    }

    public void reconnect()
    {
        logger.info("由于发生了异常，正在尝试重连");
        try {
            if(conn!=null&&!conn.isClosed())
            {
                conn.close();
            }
            connectionInternal(0);
        } catch (SQLException e1) {
            e1.printStackTrace();
        }
    }


    public boolean connectionInternal(int reconnectNumber) {
        try {
            Class.forName(driver);
            conn = DriverManager.getConnection(url, username, password);
            logger.info("【DI Client】建立与mysql数据库(URL:" + url + ")的连接");
            return true;
        } catch (Exception e) {
            logger.warn(e.getMessage(), e);

            logger.error("【DI Client】SQL:连接失败，等待重连，剩余重连次数" + reconnectNumber + " 异常信息：" + e.getLocalizedMessage());
            reconnectNumber=reconnectNumber-1;
            if (reconnectNumber <= 0) {
                logger.error("【DI Client】SQL:重连失败，DIClient连接启动失败");
                return false;
            }
            try {
                Thread.sleep(10000);
            } catch (Exception e1) {
                logger.info("【DI Client】SQL:等待失败，进程退出");
            }
            return this.connectionInternal(reconnectNumber);
        }
    }
    public void close() throws SQLException {
        if(conn!=null&&!conn.isClosed())
        {
            conn.close();
        }
    }

    public int getTotal()
    {
        String sql = "select count(*) from TBDIPDI where status='N' ";
        ResultSet myResult = null;
        PreparedStatement pre = null;
        try {
            pre = conn.prepareStatement(sql);
            myResult = pre.executeQuery();
            while (myResult.next()) {
                return myResult.getInt("count(*)");
            }
        } catch (Exception e) {
            logger.error("【DB】SQL语句" + sql + "执行失败，请检查配置文件是否正确，以及数据表是否更改:" + e.getLocalizedMessage(), e);
            reconnect();
        } finally {
            closeObj(myResult);
            closeObj(pre);
        }
        return 0;
    }

    public List<PDIOVo> getPDIOs(int limit)
    {
        List<PDIOVo> rt=new ArrayList<>();
        String sql = "select timestamp,serialno,queueid,header,data,status,processtime,description from TBDIPDI where status='N' order by TIMESTAMP,SerialNo asc  limit "+limit;
        ResultSet myResult = null;
        PreparedStatement pre = null;
        try {
            pre = conn.prepareStatement(sql);
            myResult = pre.executeQuery();
            while (myResult.next()) {
                PDIOVo pdioVo=new PDIOVo();
                pdioVo.setTimeStamp(myResult.getLong("timestamp"));
                pdioVo.setSerialNo(myResult.getInt("serialno"));
                pdioVo.setQueueId(myResult.getString("queueid"));
                pdioVo.setHeader(myResult.getString("header"));
                pdioVo.setData(myResult.getString("data"));
                pdioVo.setStatus(myResult.getString("status"));
                pdioVo.setProcessTime(myResult.getString("processtime"));
                pdioVo.setDescription(myResult.getString("description"));
                rt.add(pdioVo);
            }
        } catch (Exception e) {
            logger.error("【DB】SQL语句" + sql + "执行失败，请检查配置文件是否正确，以及数据表是否更改:" + e.getLocalizedMessage(), e);
            reconnect();

        } finally {
            closeObj(myResult);
            closeObj(pre);
        }
        return rt;
    }

    private void closeObj(Object obj) {
        if (obj == null) {
            return;
        }
        if (obj instanceof PreparedStatement) {
            PreparedStatement prepare = (PreparedStatement) obj;
            try {
                prepare.close();
                return;
            } catch (Exception e) {
            }
        }
        if (obj instanceof ResultSet) {
            ResultSet resultSet = (ResultSet) obj;
            try {
                resultSet.close();
                return;
            } catch (Exception e) {
            }
        }

        throw new BusinessException("not support type" + obj.getClass());
    }

    public void updateStatus(List<PDIOVo> pdioVos,char status,String desc)
    {
        if(pdioVos==null||pdioVos.size()==0)
        {
            return;
        }
        String inStr="(";
        for(PDIOVo pdioVo:pdioVos)
        {
            inStr+="("+pdioVo.getTimeStamp()+","+pdioVo.getSerialNo()+"),";
        }
        if(inStr.contains("),"))
        {
            inStr=inStr.substring(0,inStr.length()-1);
        }
        inStr+=")";
        List<PDIOVo> rt=new ArrayList<>();

        Date date=new Date();
        DateFormat format = new SimpleDateFormat("yyyyMMddHHmmss");
        String sql = "update TBDIPDI set status='"+status+"', processtime='"+format.format(date)+"'"+ (StringUtils.isBlank(desc)?"":",description='"+desc+"'") +" where (timestamp,serialno) in "+ inStr;
        int myResultCount = 0;
        PreparedStatement pre = null;
        try {
            pre = conn.prepareStatement(sql);
            myResultCount = pre.executeUpdate();
            if(myResultCount!=pdioVos.size())
            {
                logger.error("【DB】部分数据更新失败，入参"+pdioVos.size()+"条，更新了"+myResultCount+"条");
            }
        } catch (Exception e) {
            logger.error("【DB】SQL语句" + sql + "执行失败，请检查配置文件是否正确，以及数据表是否更改:" + e.getLocalizedMessage(), e);
            reconnect();
        } finally {
            closeObj(pre);
        }
    }

    public void addPDIOs(PDIOVo pdioVos)
    {
        String sql = "insert into TBDIPDO (TBDIPDO.`TimeStamp`,TBDIPDO.SerialNo,TBDIPDO.QueueId,TBDIPDO.Header,TBDIPDO.`Data`,TBDIPDO.`Status`) value ("+pdioVos.getTimeStamp()+","+pdioVos.getSerialNo()+",'"+pdioVos.getQueueId()+"','"+pdioVos.getHeader()+"','"+pdioVos.getData()+"','"+pdioVos.getStatus()+"')";
        int myResultCount = 0;
        PreparedStatement pre = null;
        try {
            pre = conn.prepareStatement(sql);
            myResultCount = pre.executeUpdate();
            if(myResultCount!=1)
            {
                logger.error("【DB】部分数据插入失败");
            }
        } catch (Exception e) {
            logger.error("【DB】SQL语句" + sql + "执行失败，请检查配置文件是否正确，以及数据表是否更改:" + e.getLocalizedMessage(), e);
            reconnect();
        } finally {
            closeObj(pre);
        }
    }
}
