package cn.newfeifan.mall.framework.common.util.servlet;

import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.servlet.ServletUtil;
import cn.newfeifan.mall.framework.common.util.json.JsonUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.MediaType;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.io.RandomAccessFile;
import java.net.URLEncoder;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Map;

import static cn.hutool.core.io.FileUtil.getAbsolutePath;

/**
 * 客户端工具类
 *
 * @author 非繁源码
 */
@Slf4j
public class ServletUtils {

    /**
     * 返回 JSON 字符串
     *
     * @param response 响应
     * @param object   对象，会序列化成 JSON 字符串
     */
    @SuppressWarnings("deprecation") // 必须使用 APPLICATION_JSON_UTF8_VALUE，否则会乱码
    public static void writeJSON(HttpServletResponse response, Object object) {
        String content = JsonUtils.toJsonString(object);
        ServletUtil.write(response, content, MediaType.APPLICATION_JSON_UTF8_VALUE);
    }

    /**
     * 返回附件
     *
     * @param response 响应
     * @param filename 文件名
     * @param content  附件内容
     * @param request
     */
    public static void writeAttachment(HttpServletResponse response, String filename, byte[] content, HttpServletRequest request) throws IOException {
        // 设置 header 和 contentType
        if (filename.contains("mp4")) {
            response.setHeader("Content-Disposition", "inline");
            response.setContentType("video/mp4");
            response.setHeader("Accept-Ranges","bytes");
            response.setHeader("Cache-Control","no-cache");
            response.setHeader("Access-Control-Allow-Origin","*");
        } else {
            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(filename, "UTF-8"));
            response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
        }
        // 输出附件
        IoUtil.write(response.getOutputStream(), false, content);
    }

    /**
     * 为了适配ios能够视频浏览,在文件溜获取的位置加上一些头部信息
     * @param content 内容
     * @param reqRange range
     * @param response 响应体
     */
    public static void transfer(byte[] content, String reqRange, HttpServletResponse response,String path){
        try {
            File sf = fileTransition(content,path);
            log.info("=====file文件:{}",sf);
            RspInfo ri= getPartFileRsp( sf, reqRange) ;
            response.setContentLength((int)ri.content_Length);
            response.setHeader("Content-Range", ri.content_Range);
            response.setHeader("Accept-Ranges", "bytes");
            response.setHeader("Content-Disposition", "inline");
            response.setContentType("video/mp4");
            response.setHeader("Access-Control-Allow-Origin","*");
            response.setHeader("Cache-Control","no-cache");
            response.setStatus(206);
            sendToClient(ri, response.getOutputStream(), sf);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    public static RspInfo getPartFileRsp(File sf,String reqRange) throws Exception {
        RspInfo rinfo = new RspInfo();

/* 1、Range 类型 1)bytes=x...- 2)bytes=x...-x... //Range:(unit=first byte pos)-[last byte pos]
如：Range: bytes=0- Range: bytes=0-801

2、对应 Content-Range: bytes x...(开始读取位置)-y...（读取结束位置）/z...(文件总大小) //Content-Range: bytes (unit first byte pos) - [last byte pos]/[entity legth]
如：Content-Range: bytes 0-800/801 //801:文件总大小
*/
        if(null!=reqRange){
            String[] ranplits= reqRange.split("=");
            if(ranplits.length!=2)throw new Exception("range format wrong ");
            String lenstr=ranplits[1];
            String[] flens=lenstr.split("-",-1);
            if(flens.length!=2)throw new Exception("rangelen format wrong ");
            long fpos =Long.valueOf(flens[0]);
            long lpos= flens[1].length()>0?Long.valueOf(flens[1]):sf.length()-1; //表示文件读取文件大小

            rinfo.skipLenth=fpos;
            rinfo.content_Length= lpos > 0? lpos-fpos-1:sf.length()-(fpos > 0?fpos-1:0);
//            rinfo.content_Length=sf.length();
            rinfo.content_Range=ranplits[0]+" "+fpos+"-"+lpos+"/"+sf.length();
        }
        return rinfo;
    }

    public static void sendToClient(RspInfo rinfo , OutputStream os, File sf) {

        RandomAccessFile raf;
        try {
            raf = new RandomAccessFile(sf, "r");
            byte[] b=new byte[102400];
            raf.seek(rinfo.skipLenth);
            long readlen=rinfo.content_Length; //需要读取的字节长度
            int clen=0;
            while(readlen>0&&(clen=raf.read(b))!=-1){
                if(readlen>clen){
                    os.write(b,0,clen);
                }else{
                    os.write(b,0, (int)readlen);
                }
                readlen-=clen;
            }
            raf.close();

        } catch (Exception e) {
            e.printStackTrace();
        }finally{
            if(os!=null){
                try {
                    os.flush();
                    os.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 将bute写入文件
     * @param content 内容字节
     * @return file
     * @throws IOException 异常
     */
    public static File fileTransition(byte[] content,String path) throws IOException{
        File file = new File(getAbsolutePath(path));
        log.info("======file:{}",file);
        log.info("===file.length:{}",file.length());
        if(!file.exists()){
            boolean newFile = file.createNewFile();
            log.info("=====创建文件yse or no:{}",newFile);
        }
//        Files.write(Paths.get(path), content);
        return file;
    }

    static class RspInfo{
        public long content_Length=-1;
        public String content_Range="";
        public long skipLenth=-1;
    }

    /**
     * @param request 请求
     * @return ua
     */
    public static String getUserAgent(HttpServletRequest request) {
        String ua = request.getHeader("User-Agent");
        return ua != null ? ua : "";
    }

    /**
     * 获得请求
     *
     * @return HttpServletRequest
     */
    public static HttpServletRequest getRequest() {
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        if (!(requestAttributes instanceof ServletRequestAttributes)) {
            return null;
        }
        return ((ServletRequestAttributes) requestAttributes).getRequest();
    }

    public static String getUserAgent() {
        HttpServletRequest request = getRequest();
        if (request == null) {
            return null;
        }
        return getUserAgent(request);
    }

    public static String getClientIP() {
        HttpServletRequest request = getRequest();
        if (request == null) {
            return null;
        }
        return ServletUtil.getClientIP(request);
    }

    public static boolean isJsonRequest(ServletRequest request) {
        return StrUtil.startWithIgnoreCase(request.getContentType(), MediaType.APPLICATION_JSON_VALUE);
    }

    public static String getBody(HttpServletRequest request) {
        return ServletUtil.getBody(request);
    }

    public static byte[] getBodyBytes(HttpServletRequest request) {
        return ServletUtil.getBodyBytes(request);
    }

    public static String getClientIP(HttpServletRequest request) {
        return ServletUtil.getClientIP(request);
    }

    public static Map<String, String> getParamMap(HttpServletRequest request) {
        return ServletUtil.getParamMap(request);
    }

}
