package com.ibeetl.admin.core.web;

import java.io.File;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.beetl.core.Configuration;
import org.beetl.core.GroupTemplate;
import org.beetl.core.Template;
import org.beetl.core.resource.ClasspathResourceLoader;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

import com.ibeetl.admin.core.gen.AutoGen;
import com.ibeetl.admin.core.gen.HtmlGen;
import com.ibeetl.admin.core.gen.JSGen;
import com.ibeetl.admin.core.gen.JavaCodeGen;
import com.ibeetl.admin.core.gen.MavenProjectTarget;
import com.ibeetl.admin.core.gen.MdGen;
import com.ibeetl.admin.core.gen.WebTarget;
import com.ibeetl.admin.core.gen.model.Attribute;
import com.ibeetl.admin.core.gen.model.Entity;
import com.ibeetl.admin.core.service.CoreCodeGenService;
import com.ibeetl.admin.core.util.PlatformException;

@Controller
public class CoreCodeGenController {
	private final Log log = LogFactory.getLog(this.getClass());
	private static final String MODEL = "/core/codeGen";

	@Autowired
	CoreCodeGenService codeGenService;

	@GetMapping(MODEL + "/index.do")
	public ModelAndView index() {
		ModelAndView view = new ModelAndView("/core/codeGen/index.html");
		return view;

	}
	
	@PostMapping(MODEL + "/refresh.json")
    @ResponseBody
    public JsonResult<Boolean> refresh() {
		codeGenService.refresh();
		return JsonResult.success();
	}


	@GetMapping(MODEL + "/tableDetail.do")
	public ModelAndView tableDetail(String table) {
		ModelAndView view = new ModelAndView("/core/codeGen/edit.html");
		Entity entity = codeGenService.getEntityInfo(table);
		view.addObject("entity", entity);
		return view;

	}
	
	@GetMapping(MODEL + "/project.do")
    public ModelAndView project() {
        ModelAndView view = new ModelAndView("/core/codeGen/project.html");
        File file = new  File(MavenProjectTarget.detectRootPath());
        String root = file.getParent();
        //设置生成项目为当前运行项目的上一级项目
        view.addObject("path",root+File.separator+"sample");
        view.addObject("basePackage","com.corp.xxx");
        return view;
      
    }
	
    @PostMapping(MODEL + "/projectGen.json")
    @ResponseBody
    public JsonResult project(String path,String basePackage,String includeConsole) throws IOException {
        //includeConsole 当前版本忽略，总是添加一个系统管理功能，可以在pom中移除console
        
        //生成maven项目结构
        File maven = new  File(path);
        maven.mkdirs();
        File src = new File(maven,"src");
        src.mkdirs();
        File main = new File(src,"main");
        main.mkdir();
        File test = new File(src,"test");
        test.mkdir();
        File javsSource = new File(main,"java"); 
        javsSource.mkdir();
        File resource = new File(main,"resources"); 
        resource.mkdir();
        File sql = new File(resource,"sql"); 
        sql.mkdir();
        File staticFile = new File(resource,"static"); 
        staticFile.mkdir();
        File templatesFile = new File(resource,"templates"); 
        templatesFile.mkdir();
        
        String codePath = basePackage.replace(".", "/");
        File codeFile = new File(javsSource,codePath);
        codeFile.mkdirs();
        Configuration conf = Configuration.defaultConfiguration();
        String tempalteRoot = "codeTemplate/maven/";
        ClasspathResourceLoader loader = new ClasspathResourceLoader(Thread.currentThread().getContextClassLoader(),tempalteRoot);
        GroupTemplate gt = new GroupTemplate(loader,conf);
        FileWriter fw = null;
        
        //先生成入口程序
        Template mainJavaTempalte = gt.getTemplate("/main.java");
        mainJavaTempalte.binding("basePackage", basePackage);
        fw = new FileWriter(new File(codeFile,"MainApplication.java"));
        mainJavaTempalte.renderTo(fw);
       
        
        //生成pom文件
        Template pomTemplate = gt.getTemplate("/pomTemplate.xml");
        int index = basePackage.lastIndexOf(".");
        String projectGrop = basePackage.substring(0, index);
        String projectName = basePackage.substring(index+1);
        pomTemplate.binding("group", projectGrop);
        pomTemplate.binding("project", projectName);
        fw = new FileWriter(new File(maven,"pom.xml"));
        pomTemplate.renderTo(fw);
        
        //复制当前项目的配置文件
        File config = copy(resource,"application.properties");
        copy(resource,"beetl.properties");
        copy(resource,"btsql-ext.properties");
        copy(resource,"banner.txt");
   
        return JsonResult.success();
    }
    
    
    private File copy(File root,String fileName) throws IOException {
        ClassLoader loader = Thread.currentThread().getContextClassLoader();
        InputStream input = loader.getResourceAsStream(fileName);
        if(input==null) {
            log.info("copy "+fileName+" error,不存在"); 
            return null;
        }
        
        File target = new File(root,fileName);
        FileOutputStream output = new FileOutputStream(target);
        try {
                
            byte[] buf = new byte[1024];        
            int bytesRead;        
            while ((bytesRead = input.read(buf)) > 0) {
                output.write(buf, 0, bytesRead);
            }
         } finally {
             input.close();
             output.close();
         }
        return target;
    }
	
	
	

	@PostMapping(MODEL + "/table.json")
	@ResponseBody
	public JsonResult<List<Entity>> getTable() {
		List<Entity> list = codeGenService.getAllEntityInfo();
		return JsonResult.success(list);
	}

	@PostMapping(MODEL + "/tableDetail.json")
	@ResponseBody
	public JsonResult<Entity> getInfo(String table) {
		Entity entity = codeGenService.getEntityInfo(table);
		if (entity == null) {
			JsonResult.failMessage("表不存在");
		}
		return JsonResult.success(entity);

	}

	@PostMapping(MODEL + "/gen.json")
	@ResponseBody
	public JsonResult gen(EntityInfo data,String path) {
		Entity  entity = getEntitiyInfo(data);
		String urlBase = data.getUrlBase();
		String basePackage = data.getBasePackage();
		
		MavenProjectTarget target = new MavenProjectTarget(entity, basePackage);
		//生成到path目录下，按照maven工程解构生成
		File file = new File(path);
		if(!file.exists()) {
		    throw new PlatformException("路径不存在 "+path);
		}
		target.setTargetPath(path);
		target.setUrlBase(urlBase);

		JSGen jsGen = new JSGen();
		jsGen.make(target, entity);

		HtmlGen htmlGen = new HtmlGen();
		htmlGen.make(target, entity);
		String  preffix =  urlBase.replace('/', '.');
		String basicFunctionCode = preffix+"."+entity.getCode();
		JavaCodeGen javaGen = new JavaCodeGen(basePackage, entity,basicFunctionCode);
		javaGen.make(target, entity);

		MdGen mdGen = new MdGen();
		mdGen.make(target, entity);
		if(entity.isAutoAddMenu()||entity.isAutoAddFunction()) {
			//自动增加功能点
			long  functionId = this.codeGenService.insertFunction(entity, urlBase);
			if(entity.isAutoAddMenu()) {
				this.codeGenService.insertMenu(functionId, entity, urlBase);
			}
		}
		
		
		
		return JsonResult.success();

	}
	
	@PostMapping(MODEL + "/getPath.json")
    @ResponseBody
    public JsonResult<String> getPath() {
	    String path = MavenProjectTarget.detectRootPath();
	    return JsonResult.success(path);
	}

	@PostMapping(MODEL + "/html.json")
	@ResponseBody
	public JsonResult<Map<String, String>> html(EntityInfo data) {
		
		Entity entity = getEntitiyInfo(data);
		String urlBase = data.getUrlBase();
		String basePackage = data.getBasePackage();
		WebTarget webTarget = new WebTarget(entity, basePackage);
		webTarget.setUrlBase(urlBase);
		HtmlGen htmlGen = new HtmlGen();
		htmlGen.make(webTarget, entity);
		Map<String, String> content = new HashMap<String, String>();
		for (Entry<Object, String> entry : webTarget.map.entrySet()) {
			AutoGen gen = (AutoGen) entry.getKey();
			String code = entry.getValue();
			content.put(gen.getName(), code);
		}
		return JsonResult.success(content);

	}
	
	@PostMapping(MODEL + "/js.json")
	@ResponseBody
	public JsonResult<Map<String, String>> js(EntityInfo data) {
		
		Entity entity = getEntitiyInfo(data);
		String urlBase = data.getUrlBase();
		String basePackage = data.getBasePackage();
		WebTarget webTarget = new WebTarget(entity, basePackage);
		webTarget.setUrlBase(urlBase);
		JSGen jsGen = new JSGen();
		jsGen.make(webTarget, entity);
		Map<String, String> content = new HashMap<String, String>();
		for (Entry<Object, String> entry : webTarget.map.entrySet()) {
			AutoGen gen = (AutoGen) entry.getKey();
			String code = entry.getValue();
			content.put(gen.getName(), code);
		}
		return JsonResult.success(content);

	}
	
	@PostMapping(MODEL + "/java.json")
	@ResponseBody
	public JsonResult<Map<String, String>> javaCode(EntityInfo data) {
		
		Entity entity = getEntitiyInfo(data);
		String urlBase = data.getUrlBase();
		String basePackage = data.getBasePackage();
		WebTarget webTarget = new WebTarget(entity, basePackage);
		webTarget.setUrlBase(urlBase);
		
		String  preffix =  urlBase.replace('/', '.');
		String basicFunctionCode = preffix+"."+entity.getCode();
		JavaCodeGen javaGen = new JavaCodeGen(basePackage,entity,basicFunctionCode);
		javaGen.make(webTarget, entity);
		Map<String, String> content = new HashMap<String, String>();
		for (Entry<Object, String> entry : webTarget.map.entrySet()) {
			AutoGen gen = (AutoGen) entry.getKey();
			String code = entry.getValue();
			content.put(gen.getName(), code);
		}
		
		
		return JsonResult.success(content);

	}
	
	@PostMapping(MODEL + "/sql.json")
	@ResponseBody
	public JsonResult<Map<String, String>> sql(EntityInfo data) {
		
		Entity entity = getEntitiyInfo(data);
		String urlBase = data.getUrlBase();
		String basePackage = data.getBasePackage();
		WebTarget webTarget = new WebTarget(entity, basePackage);
		webTarget.setUrlBase(urlBase);
		MdGen javaGen = new MdGen();
		javaGen.make(webTarget, entity);
		Map<String, String> content = new HashMap<String, String>();
		for (Entry<Object, String> entry : webTarget.map.entrySet()) {
			AutoGen gen = (AutoGen) entry.getKey();
			String code = entry.getValue();
			content.put(gen.getName(), code);
		}
		return JsonResult.success(content);

	}
	
	private Entity getEntitiyInfo(EntityInfo data) {
		Entity info = data.getEntity();
		String urlBase = data.getUrlBase();
		String basePackage = data.getBasePackage();
		Entity entity = codeGenService.getEntityInfo(info.getTableName());
		entity.setCode(info.getCode());
		entity.setDisplayName(info.getDisplayName());
		entity.setSystem(info.getSystem());
		entity.setAttachment(data.entity.isAttachment());
		entity.setIncludeExcel(data.entity.isIncludeExcel());
		entity.setAutoAddFunction(info.isAutoAddFunction());
		entity.setAutoAddMenu(info.isAutoAddFunction());
		for (int i = 0; i < entity.getList().size(); i++) {
		    Attribute attr = entity.getList().get(i);
		    attr.setDisplayName(info.getList().get(i).getDisplayName());
		    attr.setShowInQuery(info.getList().get(i).isShowInQuery());
		    attr.setDictType(info.getList().get(i).getDictType());
		    attr.setVerifyList(info.getList().get(i).getVerifyList());
		    if(attr.getName().equals(data.getNameAttr())) {
		        entity.setNameAttribute(attr);
		    }
		}
		
		if (StringUtils.isEmpty(entity.getCode()) || StringUtils.isEmpty(entity.getSystem())) {
			throw new PlatformException("code,system不能为空");
		}
		
		
		return entity;
	}
	

	

	@GetMapping(MODEL + "/{table}/test.json")
	@ResponseBody
	public void test(@PathVariable String table) {
		String urlBase = "cms";
		Entity entity = new Entity();
		entity.setCode("blog");
		entity.setName("CmsBlog");
		entity.setDisplayName("博客");
		entity.setTableName("CMS_BLOG");
		entity.setSystem("console");
		

		Attribute idAttr = new Attribute();
		idAttr.setColName("id");
		idAttr.setJavaType("Long");
		idAttr.setName("id");
		idAttr.setDisplayName("编号");
		idAttr.setId(true);
		entity.setIdAttribute(idAttr);

		Attribute nameAttr = new Attribute();
		nameAttr.setColName("title");
		nameAttr.setJavaType("String");
		nameAttr.setName("title");
		nameAttr.setDisplayName("标题");
		nameAttr.setShowInQuery(true);

		Attribute contentAttr = new Attribute();
		contentAttr.setColName("content");
		contentAttr.setJavaType("String");
		contentAttr.setName("content");
		contentAttr.setDisplayName("内容");
		contentAttr.setShowInQuery(true);

		Attribute createTimeAttr = new Attribute();
		createTimeAttr.setColName("create_time");
		createTimeAttr.setJavaType("Date");
		createTimeAttr.setName("createTime");
		createTimeAttr.setDisplayName("创建日期");
		createTimeAttr.setShowInQuery(true);

		Attribute createUserIdAttr = new Attribute();
		createUserIdAttr.setColName("create_user_id");
		createUserIdAttr.setJavaType("Long");
		createUserIdAttr.setName("createUserId");
		createUserIdAttr.setDisplayName("创建人");
		createUserIdAttr.setShowInQuery(true);

		Attribute typeAttr = new Attribute();
		typeAttr.setColName("type");
		typeAttr.setJavaType("String");
		typeAttr.setName("type");
		typeAttr.setDisplayName("博客类型");
		typeAttr.setShowInQuery(true);

		entity.getList().add(idAttr);
		entity.getList().add(nameAttr);
		entity.getList().add(contentAttr);
		entity.getList().add(createTimeAttr);
		entity.getList().add(createUserIdAttr);
		entity.getList().add(typeAttr);

		entity.setNameAttribute(nameAttr);
		entity.setComment("这是一个测试模型");
		// ConsoleTarget target = new ConsoleTarget();

		String basePackage = "com.ibeetl.admin.console";
		MavenProjectTarget target = new MavenProjectTarget(entity, basePackage);
		target.setUrlBase("admin");

		JSGen jsGen = new JSGen();
		jsGen.make(target, entity);

		HtmlGen htmlGen = new HtmlGen();
		htmlGen.make(target, entity);
		String  preffix =  urlBase.replace('/', '.');
		String basicFunctionCode = preffix+"."+entity.getCode();
		JavaCodeGen javaGen = new JavaCodeGen(basePackage, entity,basicFunctionCode);
		javaGen.make(target, entity);

		MdGen mdGen = new MdGen();
		mdGen.make(target, entity);

	}

}

class EntityInfo {
	Entity entity;
	String urlBase;
	String basePackage;
	String nameAttr;


	public Entity getEntity() {
		return entity;
	}

	public void setEntity(Entity entity) {
		this.entity = entity;
	}

	public String getUrlBase() {
		return urlBase;
	}

	public void setUrlBase(String urlBase) {
		this.urlBase = urlBase;
	}

	public String getBasePackage() {
		return basePackage;
	}

	public void setBasePackage(String basePackage) {
		this.basePackage = basePackage;
	}

    public String getNameAttr() {
        return nameAttr;
    }

    public void setNameAttr(String nameAttr) {
        this.nameAttr = nameAttr;
    }

   

}
