package com.example.action;

import com.example.frame.base.BaseResponse;
import com.example.frame.base.Error;
import com.example.frame.base.ErrorType;
import com.example.frame.base.Token;
import com.example.frame.utils.LocalData;
import com.example.frame.utils.LogUtil;
import com.example.frame.utils.MD5Util;
import com.example.frame.utils.MapperUtil;
import com.example.frame.utils.Message;
import com.example.frame.utils.ProcessUtil;
import com.example.frame.utils.ValidationUtil;
import com.example.module.admin.ent.Mapping;
import com.example.module.admin.ent.NginxCtrl;
import com.example.module.admin.mgr.MappingManager;
import com.example.module.admin.req.LoginRequest;
import com.example.module.admin.req.MappingCreateRequest;
import com.example.module.admin.req.MappingDeleteRequest;
import com.example.module.admin.req.MappingFindRequest;
import com.example.module.admin.req.MappingUpdateRequest;
import com.example.module.admin.rsp.LoginResponse;
import com.example.module.admin.rsp.MappingFindResponse;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer;
import xyz.wbsite.wsqlite.ObjectClient;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Controller
public class AjaxController {

    @Autowired
    private MappingManager mappingManager;
    @Autowired
    private NginxCtrl nginxCtrl;
    @Autowired
    private ObjectClient objectClient;
    @Autowired
    private FreeMarkerConfigurer freeMarkerConfigurer;
    @Value("${admin.username}")
    private String username;
    @Value("${admin.password}")
    private String password;

    @RequestMapping("/ajax")
    @ResponseBody
    public BaseResponse ajax(@RequestParam("method") String method, HttpServletRequest request, HttpServletResponse response) {

        BaseResponse baseResponse = new BaseResponse();
        String jsonString = null;
        try {
            if (method == null) {
                baseResponse.addError(new Error(ErrorType.BUSINESS_ERROR, "请求方法不能为空!"));
                return baseResponse;
            }
            Token token = LocalData.getToken();
            if (token == null) {
                token = LocalData.getTempToken();
            }
            if (!token.hasResource(method)) {
                baseResponse.addError(new Error(ErrorType.BUSINESS_ERROR, "无权调用该接口!"));
                return baseResponse;
            }

            InputStreamReader isr = new InputStreamReader(request.getInputStream(), "UTF-8");
            BufferedReader in = new BufferedReader(isr);
            jsonString = in.readLine();

            switch (method) {
                case "ajax.login":
                    baseResponse = login(jsonString, token);
                    break;
                case "nginx.start":
                    baseResponse = nginxStart(jsonString, token);
                    break;
                case "nginx.stop":
                    baseResponse = nginxStop(jsonString, token);
                    break;
                case "nginx.reload":
                    baseResponse = nginxReload(jsonString, token);
                    break;
                case "ajax.admin.mapping.find":
                    baseResponse = findMapping(jsonString, token);
                    break;
                // 创建映射
                case "ajax.admin.mapping.create":
                    baseResponse = createMapping(jsonString, token);
                    flushConfig();
                    break;
                // 删除映射
                case "ajax.admin.mapping.delete":
                    baseResponse = deleteMapping(jsonString, token);
                    flushConfig();
                    break;
                // 修改映射
                case "ajax.admin.mapping.update":
                    baseResponse = updateMapping(jsonString, token);
                    flushConfig();
                    break;
                case "ajax.admin.config.flush":
                    flushConfig();
                    baseResponse = new BaseResponse();
                    break;
                default:
                    baseResponse.addError(ErrorType.INVALID_PARAMETER, Message.NOT_EXIST_METHOD);
                    break;
            }

        } catch (Exception ex) {
            baseResponse.addError(ErrorType.SYSTEM_ERROR, Message.ERROR_500);
            LogUtil.dumpException(ex);
        } finally {
            if (baseResponse.hasError()) {
                LogUtil.e("请求方法" + method + ", 请求参数：" + jsonString);
                LogUtil.e("返回结果包含异常" + MapperUtil.toJson(baseResponse));
            }
        }
        return baseResponse;
    }

    private BaseResponse login(String jsonString, Token token) {
        LoginRequest loginRequest = MapperUtil.toJava(jsonString, LoginRequest.class);
        LoginResponse loginResponse = new LoginResponse();
        ValidationUtil.validate(loginRequest, loginResponse);
        if (loginResponse.hasError()) {
            return loginResponse;
        }
        if (!loginRequest.getUsername().equals(username)) {
            loginResponse.addError(ErrorType.BUSINESS_ERROR, "用户不存在!");
            return loginResponse;
        }

        if (!loginRequest.getPassword().equals(password)) {
            loginResponse.addError(ErrorType.BUSINESS_ERROR, "密码错误!");
            return loginResponse;
        }

        String yyyyMMdd = new SimpleDateFormat("yyyyMMdd").format(new Date());
        String encode = MD5Util.encode(yyyyMMdd + username + password);
        LocalData.getResponse().addCookie(new Cookie("token", encode));
        return loginResponse;
    }

    private BaseResponse nginxStart(String jsonString, Token token) {
        BaseResponse baseResponse = new BaseResponse();
        if (nginxCtrl.isRunning()) {
            baseResponse.addError(ErrorType.BUSINESS_ERROR, "程序已经运行");
            return baseResponse;
        }
        ProcessUtil.execBat(nginxCtrl.getStartCmd());
        return baseResponse;
    }

    private BaseResponse nginxStop(String jsonString, Token token) {
        BaseResponse baseResponse = new BaseResponse();
        if (!nginxCtrl.isRunning()) {
            baseResponse.addError(ErrorType.BUSINESS_ERROR, "程序尚未运行");
            return baseResponse;
        }
        ProcessUtil.execBat(nginxCtrl.getStopCmd());
        return baseResponse;
    }

    private synchronized BaseResponse nginxReload(String jsonString, Token token) {
        BaseResponse baseResponse = new BaseResponse();
        if (!nginxCtrl.isRunning()) {
            baseResponse.addError(ErrorType.BUSINESS_ERROR, "程序尚未运行");
            return baseResponse;
        }
        // 刷新配置文件
        flushConfig();
        // 重新加载配置文件
        ProcessUtil.execBat(nginxCtrl.getReloadCmd());
        return baseResponse;
    }

    /**
     * 创建映射
     */
    private BaseResponse createMapping(String jsonString, Token token) {
        MappingCreateRequest request = MapperUtil.toJava(jsonString, MappingCreateRequest.class);
        return mappingManager.create(request, token);
    }

    /**
     * 删除映射
     */
    private BaseResponse deleteMapping(String jsonString, Token token) {
        MappingDeleteRequest request = MapperUtil.toJava(jsonString, MappingDeleteRequest.class);
        return mappingManager.delete(request, token);
    }

    /**
     * 修改映射
     */
    private BaseResponse updateMapping(String jsonString, Token token) {
        MappingUpdateRequest request = MapperUtil.toJava(jsonString, MappingUpdateRequest.class);
        return mappingManager.update(request, token);
    }

    /**
     * 查询映射
     */
    private BaseResponse findMapping(String jsonString, Token token) {
        MappingFindRequest request = MapperUtil.toJava(jsonString, MappingFindRequest.class);
        return mappingManager.find(request, token);
    }

    private synchronized void flushConfig() {
        Writer wr = null;
        try {
            File config = nginxCtrl.getConfig();
            HashMap<String, Object> context = new HashMap<>();

            MappingFindRequest mappingFindRequest = new MappingFindRequest();
            mappingFindRequest.setPageSize(0);
            mappingFindRequest.setSortKey("SERVICE_PORT");
            MappingFindResponse mappingFindResponse = mappingManager.find(mappingFindRequest, LocalData.getSysToken());

            Map<String, List<Mapping>> services = new HashMap<>();

            for (Mapping mapping : mappingFindResponse.getResult()) {

                List<Mapping> mappings = services.get(mapping.getServicePort());

                if (mappings == null) {
                    mappings = new ArrayList<>();
                    services.put(mapping.getServicePort(), mappings);
                }
                mappings.add(mapping);
            }

            context.put("services", services);
            Template template = freeMarkerConfigurer.getConfiguration().getTemplate("nginx.conf.ftl");
            wr = new OutputStreamWriter(new FileOutputStream(config), "UTF-8");
            //写入
            template.process(context, wr);
            //关闭流
            wr.close();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (TemplateException e) {
            e.printStackTrace();
        } finally {
            try {
                wr.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
