package xyz.wbsite.action;

import org.apache.commons.io.FileUtils;
import xyz.wbsite.frame.base.FileUploadResponse;
import xyz.wbsite.frame.base.BaseResponse;
import xyz.wbsite.frame.base.ErrorType;
import xyz.wbsite.frame.base.Screen;
import xyz.wbsite.frame.utils.LocalData;
import xyz.wbsite.config.ActionConfig;
import org.springframework.beans.BeansException;
import org.springframework.boot.web.servlet.error.ErrorController;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;

import org.springframework.beans.factory.annotation.Value;

import java.nio.file.Files;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 全局请求Controller，如果无特殊请求，则不需再增加其他Controller
 * 全局htm后缀入口{@link GlobalController#hold}
 * 全局异常捕捉{@link GlobalController#excepitonHandler}
 * 全局上传接口{@link GlobalController#upload}
 * 全局下载接口{@link GlobalController#download}
 * <p>
 * 说明Request命名规则，驼峰式命名
 * Api#Example#Request ==> 目标#动作#Request
 *
 * @author author
 * @version 0.0.1
 * @since 2019-06-16
 */
@Controller
@ControllerAdvice
public class GlobalController implements ErrorController {

    @Value("${web.welcome.page}")
    private String homePage;

    /**
     * 全局异常捕捉
     *
     * @param request
     * @param response
     * @param exception 要捕获的异常
     * @return
     */
    @ExceptionHandler(Exception.class)
    public String excepitonHandler(HttpServletRequest request, HttpServletResponse response, Model model, Exception exception) {
        StringBuffer msg = new StringBuffer("");
        if (exception != null) {
            msg = new StringBuffer("");
            String message = exception.toString();
            int length = exception.getStackTrace().length;
            if (length > 0) {
                msg.append("<a>").append(message).append("</a><br>");
                for (int i = 0; i < length; i++) {
                    msg.append("<a>").append(exception.getStackTrace()[i]).append("</a><br>");
                }
            } else {
                msg.append(message);
            }
        }
        response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
        model.addAttribute("msg", msg.toString());
        return "500";
    }

    private final static String ERROR_PATH = "/error";

    @Override
    public String getErrorPath() {
        return ERROR_PATH;
    }

    @RequestMapping(value = ERROR_PATH)
    public String error(HttpServletRequest request) {
        Integer statusCode = (Integer) request.getAttribute("javax.servlet.error.status_code");

        switch (statusCode) {
            case 404:
                return "404";
            case 403:
                return "403";
            case 500:
                return "500";
            default:
                return "403";
        }
    }

    @RequestMapping("/")
    public String home() {
        return "forward:" + homePage;
    }

    /**
     * 当未明确指定控制器时，走该请求，默认返回对应的layout布局和screen视图
     * 当需要使用layout时，不需要返回值，ViewNameTranslator会处理对应关系
     *
     * @param model
     * @param request
     */
    @RequestMapping({"/**/*.htm"})
    public void hold(HttpServletRequest request, Model model) {
        HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();

        // 尝试执行Target Screen执行器(服务器渲染)，不存在则直接返回视图模板(Ajax渲染)
        Screen screenExec = null;
        try {
            String target = LocalData.getTarget();
            target = target.replaceAll("/", ".").toLowerCase();
            screenExec = LocalData.getApplicationContext().getBean(ActionConfig.SCREEN_PREFIX + target, Screen.class);
            screenExec.exec(model, request, response);
        } catch (BeansException e) {

        }

        //todo 可在此获取共性数据(也可以在全局拦截器GlobalHandlerInterceptor、拦截器作用域比此更高)，
        //todo 例如用户信息等。其他业务数据在页面渲染后通过Ajax请求
    }

    @RequestMapping("/upload")
    @ResponseBody
    public String upload(HttpServletRequest request) {
        MultipartHttpServletRequest multipartHttpServletRequest = (MultipartHttpServletRequest) request;
        MultipartFile target = multipartHttpServletRequest.getFile("file");
        String path = multipartHttpServletRequest.getParameter("path");
        String fileName = target.getOriginalFilename();
        File file = new File(root, path + fileName);

        if (file.exists()) {
            int i = 1;
            do {
                int l = fileName.lastIndexOf(".");
                file = new File(root, path + fileName.substring(0, l) + "(" + i + ")" + fileName.substring(l));
                i++;
            } while (file.exists());
        }


        //========
        //处理文件
        //========
        try {
            target.transferTo(file);
        } catch (IOException e) {
            e.printStackTrace();
        }

        return "";
    }

    @Value("${file.root.path}")
    private String root;

    @RequestMapping("/download")
    @ResponseBody
    public ResponseEntity<byte[]> download(@RequestParam(value = "file", required = false) String file) throws IOException {

        File downFile = new File(root, file);

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
        headers.setContentDispositionFormData("attachment", new String(downFile.getName().getBytes("UTF-8"), "iso-8859-1"));

        //========
        //下载DEMO
        //========


        return new ResponseEntity<byte[]>(FileUtils.readFileToByteArray(downFile),
                headers, HttpStatus.CREATED);
    }
}
