package cn.com.ctop.common.module.service.impl;

import cn.com.ctop.common.module.entity.CtopOauthToken;
import cn.com.ctop.common.module.entity.FileInfo;
import cn.com.ctop.common.module.entity.SourceFile;
import cn.com.ctop.common.module.mapper.FileInfoMapper;
import cn.com.ctop.common.module.service.ICtopOauthTokenService;
import cn.com.ctop.common.module.service.IFileInfoService;
import cn.com.ctop.common.module.service.ISourceFileService;
import cn.com.ctop.common.module.utils.*;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.http.HttpEntity;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.URI;
import java.net.URL;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @Description: 文件信息
 * @Author: jeecg-boot
 * @Date: 2019-07-28
 * @Version: V1.0
 */
@Slf4j
@Service
public class FileInfoServiceImpl extends ServiceImpl<FileInfoMapper, FileInfo> implements IFileInfoService {
    @Value("${jeecg.path.image-upload}")
    private String imageUploadPath;
    @Value("${jeecg.path.video-upload}")
    private String videoUploadPath;
    @Autowired
    FileInfoMapper fileInfoMapper;
    @Autowired
    private ISourceFileService sourceFileService;
    @Autowired
    private ICtopOauthTokenService tokenService;

    @Override
    public Map<String, Object> uploadVideoToBytedance(String accountId, String videoUrl) {
        Map<String, Object> resultMap = new HashMap<>();
        //TODO查询是否已经上传过头条平台
        CtopOauthToken token = tokenService.getOauthTokenByAccountId(accountId);
        JSONObject resultObject = uploadAdvideo(token, videoUrl, token.getAccountId() + "");
        Integer code = resultObject.getInteger("code");
        String message = resultObject.getString("message");
        if (null == code || code != 0) {
            log.info("视频文件上传失败,accountId:{},message:{}", accountId, message);
            ResultMapUtils.setResultMap(resultMap, StatusCode.BYTEDANCE_VIDEO_UPLOAD_FAIL.getCode());
            return resultMap;
        }
        FileInfo fileInfo = (FileInfo) resultObject.get("file");
        ResultMapUtils.setResultMap(resultMap, StatusCode.COMMON_SUCCESS.getCode());
        resultMap.put("videoId", fileInfo.getFileId());
        return resultMap;
    }

    @Override
    public Map<String, Object> upload3ImagesToBytedance(String accountId, String imageFileUrls) {
        Map<String, Object> resultMap = new HashMap<>();
        String[] imageUrls = imageFileUrls.split(",");
        if (null == imageUrls || imageUrls.length < 3) {
            ResultMapUtils.setResultMap(resultMap, StatusCode.IMAGE_NUMBER_SHORTAGE.getCode());
            return resultMap;
        }
        CtopOauthToken token = tokenService.getOauthTokenByAccountId(accountId);
        JSONArray imageIds = new JSONArray();
        for (int i = 0; i < imageUrls.length; i++) {
            JSONObject resultObject = uploadAdImage(token, imageUrls[i], token.getAccountId() + "");
            Integer code = resultObject.getInteger("code");
            String message = resultObject.getString("message");
            if (null == code || code != 0) {
                log.info("图片文件上传失败,accountId:{},message:{}", accountId, message);
                ResultMapUtils.setResultMap(resultMap, StatusCode.BYTEDANCE_VIDEO_UPLOAD_FAIL.getCode());
                return resultMap;
            }
            FileInfo fileInfo = (FileInfo) resultObject.get("file");
            imageIds.add(fileInfo.getFileId());
        }
        ResultMapUtils.setResultMap(resultMap, StatusCode.COMMON_SUCCESS.getCode());
        resultMap.put("imageIds", imageIds);
        return resultMap;
    }

    @Override
    public Map<String, Object> uploadImageToBytedance(String accountId, String imageUrl) {
        Map<String, Object> resultMap = new HashMap<>();
        CtopOauthToken token = tokenService.getOauthTokenByAccountId(accountId);
        JSONObject resultObject = uploadAdImage(token, imageUrl, token.getAccountId() + "");
        Integer code = resultObject.getInteger("code");
        String message = resultObject.getString("message");
        if (null == code || code != 0) {
            log.info("图片文件上传失败,accountId:{},message:{}", accountId, message);
            ResultMapUtils.setResultMap(resultMap, StatusCode.BYTEDANCE_IMAGE_UPLOAD_FAIL.getCode());
            return resultMap;
        }
        FileInfo fileInfo = (FileInfo) resultObject.get("file");
        ResultMapUtils.setResultMap(resultMap, StatusCode.COMMON_SUCCESS.getCode());
        JSONArray array = new JSONArray();
        array.add(fileInfo.getFileId());
        resultMap.put("imageIds", array);
        return resultMap;
    }

    @Override
    public List<FileInfo> getFileInfoByMd5(String md5) {
        QueryWrapper<FileInfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("md5", md5).orderByDesc("create_time");
        return fileInfoMapper.selectList(queryWrapper);
    }

    @Override
    public Map<String, Object> checkFileInfo(String code) {
        Map<String, Object> result = new HashMap<>();
        QueryWrapper<SourceFile> wrapper = new QueryWrapper<>();
        wrapper.eq("code", code).orderByDesc("id").last("limit 1");
        SourceFile file = sourceFileService.getOne(wrapper);
        if (null != file) {
            //文件已存在
            ResultMapUtils.setResultMap(result, StatusCode.FILE_HAS_UPLOAD.getCode());
            result.put("url", file.getUrl());
            return result;
        } else {
            //文件尚未上传
            ResultMapUtils.setResultMap(result, StatusCode.FILE_HAS_NOT_UPLOAD.getCode());
            return result;
        }
    }

    @Override
    public Map<String, Object> getCreativeWords(Long accountId) {
        CtopOauthToken token = tokenService.getOauthTokenByAccountId(accountId + "");
        return getCreativeWord(token, accountId);
    }

    @Override
    public JSONObject getSiteList(Long accountId) {
        return null;
    }

    @Override
    public JSONObject getCreativeWord(CtopOauthToken token, Long advertiserId) {
        // 请求地址
        String url = "https://ad.toutiao.com/open_api/2/tools/creative_word/select/";
        // 请求参数
        JSONObject data = new JSONObject();
        data.put("advertiser_id", advertiserId);
        JSONObject resultObject = HttpUtils.bytedanceGetRequest(token.getAccessToken(), url, data);
        JSONArray creativeWords = resultObject.getJSONObject("data").getJSONArray("creative_word");
        resultObject.remove("data");
        JSONArray array = new JSONArray();
        if (null != creativeWords && creativeWords.size() > 0) {
            creativeWords.forEach(word -> {
                JSONObject getWord = (JSONObject) word;
                getWord.remove("user_rate");
                getWord.remove("content_type");
                getWord.remove("default_word");
                getWord.remove("words");
                getWord.remove("max_word_len");
                array.add(getWord);
            });
        }
        resultObject.put("creative_word", array);
        return resultObject;
    }

    @Override
    public Map<String, Object> insertFile(String code, String url) {
        Map<String, Object> resultMap = new HashMap();
        FileInfo fileInfo = new FileInfo();
        fileInfo.setFileName("");
        fileInfo.setFileUrl(url);
        fileInfo.setMd5(code);
        fileInfo.setPath("");
        fileInfo.setPlatformType("");
        fileInfo.setAccountId(0L);
        fileInfo.setFileId("");
        fileInfo.setType("");
        this.saveOrUpdate(fileInfo);
        ResultMapUtils.setResultMap(resultMap, StatusCode.COMMON_SUCCESS.getCode());
        return resultMap;
    }

    public JSONObject searchIndustry(CtopOauthToken token, Integer level) {
        // 请求地址
        String url = "https://ad.toutiao.com/open_api/2/tools/industry/get/";
        if (null != level) {
            url += "?level=" + level;
        }
        return HttpUtils.bytedanceGetRequest(token.getAccessToken(), url, new JSONObject());
    }

    public JSONObject uploadAdImage(CtopOauthToken token, String imageUrl, String advertiserId) {
        JSONObject result = new JSONObject();
        //1:下载文件到本地
        String imagePath = downLoadByUrl(imageUrl);
        //2: 获取MD5值
        String md5Hex = null;
        try {
            md5Hex = DigestUtils.md5Hex(new FileInputStream(imagePath));
        } catch (IOException e) {
            e.printStackTrace();
        }
        //3: 根据MD5值查询是否已经上传过服务器
        List<FileInfo> getFileInfo = getFileInfoByMd5(md5Hex);
        //表示已经上传过服务器
        if (null != getFileInfo && getFileInfo.size() > 0) {
            result.put("code", 0);
            result.put("file", getFileInfo.get(0));
            result.put("message", "图片上传成功");
            result.put("success", true);
            return result;
        }
        QueryWrapper<FileInfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("md5", md5Hex);
        fileInfoMapper.delete(queryWrapper);

        //文件上传
        JSONObject bytedanceObject = imageUpload(token, advertiserId, imageUrl);
        if (null == bytedanceObject) {
            log.info("今日头条图片上传失败");
            result.put("code", -1);
            result.put("message", "今日头条文件上传失败");
            return result;
        }
        JSONObject data = bytedanceObject.getJSONObject("data");
        FileInfo fileInfo = new FileInfo(md5Hex, data, advertiserId, token, "https:" + imageUrl, imagePath, "IMAGE", "1");
        fileInfoMapper.insert(fileInfo);
        result.put("code", 0);
        result.put("file", fileInfo);
        result.put("message", "图片上传成功");
        result.put("success", true);
        return result;
    }

    private JSONObject imageUpload(CtopOauthToken token, String advertiserId, String imageUrl) {
        JSONObject result = null;
        // 请求地址
        String url = PropertiesUtils.getValue("bytedance_config", "bytedance_api_url") + PropertiesUtils.getValue("bytedance_config", "bytedance_v2_file_image_ad");
        // 构造请求
        HttpPost httpPost = new HttpPost(url);
        httpPost.setHeader("Access-Token", token.getAccessToken());
        MultipartEntityBuilder entityBuilder = MultipartEntityBuilder.create();
        // 其他参数
        entityBuilder.addTextBody("advertiser_id", advertiserId);
        entityBuilder.addTextBody("upload_type", BytedanceInterfaceConstant.UPLOAD_TYPE_BY_URL);
        entityBuilder.addTextBody("image_url", "https:" + imageUrl);

        HttpEntity entity = entityBuilder.build();
        CloseableHttpResponse response = null;
        CloseableHttpClient client = null;
        try {
            client = HttpClientBuilder.create().build();
            httpPost.setURI(URI.create(url));
            httpPost.setEntity(entity);
            response = client.execute(httpPost);
            if (response != null && response.getStatusLine().getStatusCode() == 200) {
                BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
                StringBuffer buffer = new StringBuffer();
                String line = "";
                while ((line = bufferedReader.readLine()) != null) {
                    buffer.append(line);
                }
                bufferedReader.close();
                return JSONObject.parseObject(buffer.toString());
            }
        } catch (ClientProtocolException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (response != null) {
                    response.close();
                }
                client.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;
    }


    @Override
    public String downLoadByUrl(String fileUrl) {
        //获取文件名，文件名实际上在URL中可以找到
        String fileName = fileUrl.substring(fileUrl.lastIndexOf("/") + 1);
        //这里服务器上要将此图保存的路径
        String savePath = this.imageUploadPath + fileName;
        try {
            /*将网络资源地址传给,即赋值给url*/
            URL url = new URL("https:" + fileUrl);
            /*此为联系获得网络资源的固定格式用法，以便后面的in变量获得url截取网络资源的输入流*/
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            DataInputStream in = new DataInputStream(connection.getInputStream());
            /*此处也可用BufferedInputStream与BufferedOutputStream*/
            DataOutputStream out = new DataOutputStream(new FileOutputStream(savePath));
            /*将参数savePath，即将截取的图片的存储在本地地址赋值给out输出流所指定的地址*/
            byte[] buffer = new byte[4096];
            int count = 0;
            /*将输入流以字节的形式读取并写入buffer中*/
            while ((count = in.read(buffer)) > 0) {
                out.write(buffer, 0, count);
            }
            out.close();/*后面三行为关闭输入输出流以及网络资源的固定格式*/
            in.close();
            connection.disconnect();
            //返回内容是保存后的完整的URL
            /*网络资源截取并存储本地成功返回true*/
            return savePath;

        } catch (Exception e) {
            return null;
        }
    }

    public JSONObject uploadAdvideo(CtopOauthToken token, String videoUrl, String advertiserId) {
        JSONObject result = new JSONObject();
        //1:下载文件到本地
        String videoPath = downLoadByUrl(videoUrl);
        //2: 获取MD5值
        String md5Hex = null;
        try {
            md5Hex = DigestUtils.md5Hex(new FileInputStream(videoPath));
        } catch (IOException e) {
            e.printStackTrace();
        }
        //3: 根据MD5值查询是否已经上传过服务器
        List<FileInfo> getFileInfo = getFileInfoByMd5(md5Hex);
        //表示已经上传过服务器
        if (null != getFileInfo && getFileInfo.size() > 0) {
            result.put("code", 0);
            result.put("file", getFileInfo.get(0));
            result.put("message", "视频上传成功");
            result.put("success", true);
            return result;
        }

        QueryWrapper<FileInfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("md5", md5Hex);
        fileInfoMapper.delete(queryWrapper);

        //文件上传
        JSONObject bytedanceObject = videoUpload(token, advertiserId, videoPath);
        if (null == bytedanceObject) {
            log.info("今日头条视频上传失败");
            result.put("code", -1);
            result.put("message", "今日头条视频上传失败");
            return result;
        }
        JSONObject data = bytedanceObject.getJSONObject("data");
        FileInfo fileInfo = new FileInfo(md5Hex, data, advertiserId, token, "https:" + videoUrl, videoPath, "VIDEO", "1");
        fileInfoMapper.insert(fileInfo);
        result.put("code", 0);
        result.put("file", fileInfo);
        result.put("message", "视频上传成功");
        result.put("success", true);
        return result;
    }

    private JSONObject videoUpload(CtopOauthToken token, String advertiserId, String videoPath) {
        CloseableHttpResponse response = null;
        CloseableHttpClient client = null;
        // 请求地址
        String url = PropertiesUtils.getValue("bytedance_config", "bytedance_api_url") + PropertiesUtils.getValue("bytedance_config", "bytedance_v2_file_video_ad");
        // 构造请求
        HttpPost httpPost = new HttpPost(url);
        httpPost.setHeader("Access-Token", token.getAccessToken());
        // 文件参数
        try {
            FileBody file = new FileBody(new File(videoPath));
            MultipartEntityBuilder entityBuilder = MultipartEntityBuilder.create()
                    .addPart("video_file", file);
            // 其他参数
            entityBuilder.addTextBody("advertiser_id", advertiserId);
            entityBuilder.addTextBody("video_signature", DigestUtils.md5Hex(new FileInputStream(new File(videoPath))));
            HttpEntity entity = entityBuilder.build();
            client = HttpClientBuilder.create().build();
            httpPost.setURI(URI.create(url));
            httpPost.setEntity(entity);
            response = client.execute(httpPost);
            if (response != null && response.getStatusLine().getStatusCode() == 200) {
                BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
                StringBuffer result = new StringBuffer();
                String line = "";
                while ((line = bufferedReader.readLine()) != null) {
                    result.append(line);
                }
                bufferedReader.close();
                return JSONObject.parseObject(result.toString());
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (response != null) {
                    response.close();
                }
                client.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;
    }

}
