package com.ebts.generator.service.impl;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.StringWriter;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

import com.ebts.common.constant.Constants;
import com.ebts.common.constant.ReturnConstants;
import com.ebts.common.core.entity.Result;
import com.ebts.common.utils.SecurityUtils;
import com.ebts.generator.dao.ApiClassDao;
import com.ebts.generator.dao.GenTableDao;
import com.ebts.generator.dao.ModuleDao;
import com.ebts.generator.dto.InterTableDto;
import com.ebts.generator.entity.ApiClass;
import com.ebts.generator.entity.Module;
import com.ebts.generator.utils.*;
import org.apache.commons.io.IOUtils;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;
import org.springframework.stereotype.Service;
import com.ebts.generator.dao.InterTableDao;
import com.ebts.generator.entity.InterTable;
import com.ebts.generator.service.InterTableService;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;

/**
 * 接口信息Service业务层处理
 *
 * @author binlin
 * @date 2021-01-25
 */
@Service
public class InterTableServiceImpl implements InterTableService {

    @Resource
    private InterTableDao interTableDao;
    @Resource
    private ApiClassDao apiclassDao;
    @Resource
    private ModuleDao moduleDao;
    @Resource
    private GenTableDao genTableDao;

    /**
     * 查询接口信息
     *
     * @param id 接口信息ID
     * @return 接口信息
     */
    @Override
    public Result<InterTable> selectInterTableById(Long id) {
        InterTable interTable = interTableDao.selectInterTableById(id);
        if (interTable != null) {
            return Result.ok(interTable);
        } else {
            return Result.info(ReturnConstants.RESULT_EMPTY);
        }
    }

    /**
     * 查询接口信息列表
     *
     * @param interTable 接口信息
     * @return 接口信息
     */
    @Override
    public Result<Map<String, Object>> selectInterTableList(InterTable interTable) {
        Map<String, Object> modeMap = new HashMap<String, Object>();
        if (interTable.getType() == 1) {
            Module module = moduleDao.selectModuleById(interTable.getmId());
            modeMap.put("info", module);
        } else if (interTable.getType() == 2) {
            ApiClass apiclass = apiclassDao.selectApiclassById(interTable.getcId());
            modeMap.put("info", apiclass);
        }
        List<InterTable> interTableList = interTableDao.selectInterTableList(interTable);
        modeMap.put("rows", interTableList);
        return Result.ok(modeMap);
    }

    /**
     * 新增接口信息
     *
     * @param interTable 接口信息
     * @return 结果
     */
    @Override
    public Result<Integer> insertInterTable(InterTable interTable) {
        interTable.setCreateBy(SecurityUtils.getUserId());
        interTableDao.insertInterTable(interTable);
        return Result.ok();
    }

    /**
     * 修改接口信息
     *
     * @param interTableDto 接口信息
     * @return 结果
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public Result<Integer> updateInterTable(InterTableDto interTableDto) {
        List<InterTable> interTables = interTableDto.getInterTables();
        if (interTableDto.getModule() == null) {
            ApiClass apiclass = interTableDto.getApiclass();
            apiclassDao.updateApiclass(apiclass);
            interTableDao.deleteInterTableByClassId(apiclass.getId());
        } else if (interTableDto.getApiclass() == null) {
            Module module = interTableDto.getModule();
            moduleDao.updateModule(module);
            interTableDao.deleteInterTableByModuleId(module.getId());
        }
        if (interTables.size() > 0) {
            for (int i = 0; i < interTables.size(); i++) {
                interTables.get(i).setCreateBy(SecurityUtils.getUserId());
            }
            interTableDao.insertInterTables(interTables);
        }
        return Result.ok();
    }

    /**
     * 批量删除接口信息
     *
     * @param ids 需要删除的接口信息ID
     * @return 结果
     */
    @Override
    public Result<Integer> deleteInterTableByIds(Long[] ids) {
        interTableDao.deleteInterTableByIds(ids);
        return Result.ok();
    }

    /**
     * 删除接口信息信息
     *
     * @param id 接口信息ID
     * @return 结果
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public Result<Integer> deleteInterTableById(Long id) {
        interTableDao.deleteInterTableById(id);
        return Result.ok();
    }

    @Override
    @Transactional(propagation = Propagation.SUPPORTS)
    public Result<Map<String, String>> previewCodeClass(Long cid) {
        Map<String, String> dataMap = new LinkedHashMap<String, String>();
        ApiClass apiclass = interTableDao.selectInterTableClass(cid);
        if (apiclass == null) {
            return Result.error(ReturnConstants.INTER_NULL);
        }
        VelocityInitializer.initVelocity();
        VelocityContext context = InterTableUtils.prepareClassContext(apiclass);
        Map<String, String> templates = InterTableUtils.getTemplateList(2);
        StringWriter sw = new StringWriter();
        Template template = Velocity.getTemplate(templates.get("java"), Constants.UTF8);
        template.merge(context, sw);
        dataMap.put(getJavaClassName(apiclass.getcName()), sw.toString());

        sw = new StringWriter();
        template = Velocity.getTemplate(templates.get("sql"), Constants.UTF8);
        template.merge(context, sw);
        dataMap.put(getSqlName(apiclass.getcName()), sw.toString());
        return Result.ok(dataMap);
    }

    @Override
    @Transactional(propagation = Propagation.SUPPORTS)
    public Result<Map<String, Object>> previewCodeModule(Long mid) {
        Map<String, Object> dataMap = new LinkedHashMap<String, Object>();
        List<InterTable> interTableList = interTableDao.selectInterTableModule(mid);
        if (interTableList.size() == 0) {
            return Result.error("该模块下接口为空,请先创建接口!");
        }
        VelocityInitializer.initVelocity();
        List<VelocityContext> contextList = InterTableUtils.prepareMoudleContext(interTableList);
        Map<String, String> templates = InterTableUtils.getTemplateList(2);
        StringWriter sqlsw = new StringWriter();
        Template sqltemplate = Velocity.getTemplate(templates.get("sql"), Constants.UTF8);
        for (VelocityContext context : contextList) {
            StringWriter sw = new StringWriter();
            Template template = Velocity.getTemplate(templates.get("java"), Constants.UTF8);
            template.merge(context, sw);
            sqltemplate.merge(context, sqlsw);
            dataMap.put(getJavaClassName((String) context.get("ClassName")), sw.toString());
        }
        dataMap.put(getSqlName("module"), sqlsw.toString());
        return Result.ok(dataMap);
    }

    @Override
    @Transactional(propagation = Propagation.SUPPORTS)
    public Result<byte[]> generatorCodeClass(Long cid) {
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        ZipOutputStream zip = new ZipOutputStream(outputStream);
        ApiClass apiclass = interTableDao.selectInterTableClass(cid);
        VelocityInitializer.initVelocity();
        VelocityContext context = InterTableUtils.prepareClassContext(apiclass);
        Map<String, String> templates = InterTableUtils.getTemplateList(2);
        StringWriter sw = new StringWriter();
        Template template = Velocity.getTemplate(templates.get("java"), Constants.UTF8);
        template.merge(context, sw);
        zip = genCode(getJavaClassName(apiclass.getcName()), zip, sw);
        if (zip == null) {
            return Result.error("代码生成失败!");
        }
        sw = new StringWriter();
        template = Velocity.getTemplate(templates.get("sql"), Constants.UTF8);
        template.merge(context, sw);

        zip = genCode(getSqlName(apiclass.getcName()), zip, sw);
        if (zip == null) {
            return Result.error("代码生成失败!");
        }
        int start = genTableDao.insertMenu(sw.toString());
        if (!(start > 0)) {
            return Result.error(ReturnConstants.SYS_ERROR);
        }
        IOUtils.closeQuietly(zip);
        return Result.ok(outputStream.toByteArray());

    }

    @Override
    @Transactional(propagation = Propagation.SUPPORTS, rollbackFor = Exception.class)
    public Result<byte[]> generatorCodeModule(Long mid) {
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        ZipOutputStream zip = new ZipOutputStream(outputStream);
        List<InterTable> interTableList = interTableDao.selectInterTableModule(mid);
        if (interTableList.size() == 0) {
            return Result.error("该模块下接口为空,请先创建接口!");
        }
        VelocityInitializer.initVelocity();
        List<VelocityContext> contextList = InterTableUtils.prepareMoudleContext(interTableList);
        Map<String, String> templates = InterTableUtils.getTemplateList(2);
        StringWriter sqlsw = new StringWriter();
        Template sqltemplate = Velocity.getTemplate(templates.get("sql"), Constants.UTF8);
        for (VelocityContext context : contextList) {
            StringWriter sw = new StringWriter();
            Template template = Velocity.getTemplate(templates.get("java"), Constants.UTF8);
            template.merge(context, sw);
            sqltemplate.merge(context, sqlsw);
            zip = genCode(getJavaClassName((String) context.get("ClassName")), zip, sw);
        }
        zip = genCode(getSqlName("module"), zip, sqlsw);
        if (zip != null) {
            int start = genTableDao.insertMenu(sqlsw.toString());
            if (!(start > 0)) {
                return Result.error(ReturnConstants.OP_ERROR);
            }
        }
        IOUtils.closeQuietly(zip);
        return Result.ok(outputStream.toByteArray());
    }


    public ZipOutputStream genCode(String className, ZipOutputStream zip, StringWriter sw) {
        try {
            zip.putNextEntry(new ZipEntry(className));
            IOUtils.write(sw.toString(), zip, Constants.UTF8);
            IOUtils.closeQuietly(sw);
            zip.flush();
            zip.closeEntry();
            return zip;
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }


    public String getJavaClassName(String cName) {
        return InterTableUtils.getUpperCase(cName) + "Controller.java";
    }

    public String getSqlName(String cName) {
        return InterTableUtils.getUpperCase(cName) + ".sql";
    }
}