package pwc.taxtech.atms.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.io.IOUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.entity.mime.content.ByteArrayBody;
import org.apache.http.entity.mime.content.StringBody;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import pwc.taxtech.atms.common.CommonUtils;
import pwc.taxtech.atms.common.config.FileServiceConfig;
import pwc.taxtech.atms.constant.Constant;
import pwc.taxtech.atms.dto.didiFileUpload.DidiFileIUploadParam;
import pwc.taxtech.atms.dto.didiFileUpload.DidiFileUploadDetailResult;
import pwc.taxtech.atms.exception.ServiceException;
import pwc.taxtech.atms.vat.dao.FileUploadLogMapper;
import pwc.taxtech.atms.vat.dao.FileUploadMapper;
import pwc.taxtech.atms.vat.entity.FileUpload;
import pwc.taxtech.atms.vat.entity.FileUploadExample;
import pwc.taxtech.atms.vat.entity.FileUploadLog;

import javax.annotation.Resource;
import java.io.IOException;
import java.security.MessageDigest;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * version 2.0
 * author kevin
 */
@Service
public class DidiFileUploadService extends BaseService {
    @Autowired
    private FileServiceConfig config;

    @Resource
    private FileUploadMapper fileUploadMapper;

    @Resource
    private FileUploadLogMapper fileUploadLogMapper;

    @Value("${env_type}")
    private String evnType;

    @Value("${file_upload_post_url}")
    private String upload_post_url;

    @Value("${file_upload_query_url}")
    private String upload_query_url;

    protected static char hexDigits[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};

    private static final String ENV_DEV = "dev";

    private static final String HTTP_SUCCESS_CODE = "200";

    private static final String PROXY_HOST = "47.94.233.173";

    private static final String PROXY_PORT = "11007";

    public FileUpload uploadFile(MultipartFile file, String bizSource) throws ServiceException {
        CloseableHttpClient httpClient = null;
        String requestKey = CommonUtils.getUUID();
        String requestUrl = upload_post_url + "/" + requestKey;
        FileUploadLog uploadLog = new FileUploadLog();
        uploadLog.setRequestId(requestKey);
        uploadLog.setRequestUrl(requestUrl);
        uploadLog.setUid(CommonUtils.getUUID());
        try {
            httpClient = HttpClients.createDefault();
            HttpPost httpPost = new HttpPost(requestUrl);
            String md5Str = getFileMD5String(file);
            ByteArrayBody byteBody = new ByteArrayBody(file.getBytes(), ContentType.MULTIPART_FORM_DATA, file.getOriginalFilename());
            StringBody md5 = new StringBody(md5Str, ContentType.create("text/plain"));
            HttpEntity httpEntity = MultipartEntityBuilder.create().addPart("filecontent", byteBody).addPart("md5", md5).build();
            httpPost.setEntity(httpEntity);
            HttpResponse httpResponse = httpClient.execute(httpPost);
            JSONObject resultDto = JSON.parseObject(IOUtils.toString(httpResponse.getEntity().getContent(), "UTF-8"));
            uploadLog.setResponsJson(resultDto.toJSONString());
            FileUpload fileUpload = null;
            if (HTTP_SUCCESS_CODE.equals(resultDto.getString("status_code"))) {
                fileUpload = new FileUpload();
                fileUpload.setBizSource(bizSource);
                fileUpload.setUid(CommonUtils.getUUID());
                fileUpload.setFileName(file.getOriginalFilename());
                fileUpload.setResourceKey(requestKey);
                assemblyModel(resultDto, fileUpload);
                uploadLog.setFileUploadId(fileUpload.getUid());
                fileUploadMapper.insert(fileUpload);
            }
            fileUploadLogMapper.insert(uploadLog);
            return fileUpload;
        } catch (Exception e) {
            uploadLog.setResponsJson(e.getMessage());
            fileUploadLogMapper.insert(uploadLog);
            logger.error("uploadFile error.", e);
        } finally {
            if (null != httpClient) {
                try {
                    httpClient.close();
                } catch (IOException e) {
                    logger.error("close httpClient error.", e);
                }
            }
        }
        throw new ServiceException("uploadFile error.");
    }

    public static String getFileMD5String(MultipartFile file) throws Exception {
        MessageDigest messagedigest = MessageDigest.getInstance("MD5");
        messagedigest.update(file.getBytes());
        byte bytes[] = messagedigest.digest();
        return bufferToHex(bytes, 0, bytes.length);
    }

    private static String bufferToHex(byte bytes[], int m, int n) {
        StringBuffer stringbuffer = new StringBuffer(2 * n);
        int k = m + n;
        for (int l = m; l < k; l++) {
            appendHexPair(bytes[l], stringbuffer);
        }
        return stringbuffer.toString();
    }

    private static void appendHexPair(byte bt, StringBuffer stringbuffer) {
        char c0 = hexDigits[(bt & 0xf0) >> 4];
        char c1 = hexDigits[bt & 0xf];
        stringbuffer.append(c0);
        stringbuffer.append(c1);
    }


    public PageInfo<DidiFileUploadDetailResult> queryPage(DidiFileIUploadParam param) {
        Page page = null;
        if (param.getPageInfo() != null && param.getPageInfo().getPageSize() != null && param.getPageInfo().getPageIndex() != null) {
            page = PageHelper.startPage(param.getPageInfo().getPageIndex(), param.getPageInfo().getPageSize());
        }
        FileUploadExample example = new FileUploadExample();
        FileUploadExample.Criteria criteria = example.createCriteria();
        if(CollectionUtils.isNotEmpty(param.getUuids())){
            criteria.andUidIn(param.getUuids());
        }
        if(CollectionUtils.isNotEmpty(param.getBizSources())){
            criteria.andBizSourceIn(param.getBizSources());
        }
        if(CollectionUtils.isNotEmpty(param.getUploadMonths())){
            criteria.andUploadMonthIn(param.getUploadMonths());
        }
        if(CollectionUtils.isNotEmpty(param.getUploadDates())){
            criteria.andUploadDateIn(param.getUploadDates());
        }
        if(CollectionUtils.isNotEmpty(param.getUploadWeeks())){
            criteria.andUploadWeekIn(param.getUploadWeeks());
        }
        if(CollectionUtils.isNotEmpty(param.getUploadYears())){
            criteria.andUploadYearIn(param.getUploadYears());
        }
        refreshViewUrl(param);
        PageInfo<DidiFileUploadDetailResult> pageInfo = new PageInfo<>(fileUploadMapper.selectByExample(example).stream()
                .map(o -> beanUtil.copyProperties(o, new DidiFileUploadDetailResult())).collect(Collectors.toList()));
        if (page != null) {
            pageInfo.setTotal(page.getTotal());
        }
        return pageInfo;
    }

    public FileUpload assemblyModel(JSONObject resultDto, FileUpload fileUpload) {
        fileUpload.setFileMd5(resultDto.getString("md5"));
        HttpPost tmpPost = new HttpPost(resultDto.getString("download_url"));
        String downloadUrlHttp = resultDto.getString("download_url");
        String downloadUrlHttps = resultDto.getString("download_url_https");
        if (ENV_DEV.equals(evnType)) {
            downloadUrlHttp = downloadUrlHttp.replace(tmpPost.getURI().getHost(), PROXY_HOST);
            downloadUrlHttp = downloadUrlHttp.replace(String.valueOf(tmpPost.getURI().getPort()), PROXY_PORT);
            downloadUrlHttps = downloadUrlHttps.replace(tmpPost.getURI().getHost(), PROXY_HOST);
            downloadUrlHttps = downloadUrlHttps.replace(String.valueOf(tmpPost.getURI().getPort()), PROXY_PORT);
        }
        fileUpload.setViewHttpsUrl(downloadUrlHttps);
        fileUpload.setViewHttpUrl(downloadUrlHttp);
        Date date = new Date();
        fileUpload.setUploadTime(date);
        SimpleDateFormat dateFormat = new SimpleDateFormat(Constant.DateFormat.YYYYMMDD);
        fileUpload.setUploadDate(dateFormat.format(date));
        dateFormat = new SimpleDateFormat(Constant.DateFormat.YYYYMM);
        fileUpload.setUploadMonth(dateFormat.format(date));
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        fileUpload.setUploadWeek(calendar.get(Calendar.WEEK_OF_YEAR));
        fileUpload.setUploadYear(calendar.get(Calendar.YEAR));
        String[] params = tmpPost.getURI().getQuery().split("&");
        Long time = new Long(params[0].replace("expire=", ""));
        Date useFullDate = new Date();
        useFullDate.setTime(new Date().getTime() + time - 7200);
        fileUpload.setUsefulEndTime(useFullDate);
        return fileUpload;
    }

    public void refreshViewUrl(DidiFileIUploadParam param) throws ServiceException {
        FileUploadExample example = new FileUploadExample();
        FileUploadExample.Criteria criteria = example.createCriteria();
        if(CollectionUtils.isNotEmpty(param.getUuids())){
            criteria.andUidIn(param.getUuids());
        }
        if(CollectionUtils.isNotEmpty(param.getBizSources())){
            criteria.andBizSourceIn(param.getBizSources());
        }
        if(CollectionUtils.isNotEmpty(param.getUploadMonths())){
            criteria.andUploadMonthIn(param.getUploadMonths());
        }
        if(CollectionUtils.isNotEmpty(param.getUploadDates())){
            criteria.andUploadDateIn(param.getUploadDates());
        }
        if(CollectionUtils.isNotEmpty(param.getUploadWeeks())){
            criteria.andUploadWeekIn(param.getUploadWeeks());
        }
        if(CollectionUtils.isNotEmpty(param.getUploadYears())){
            criteria.andUploadYearIn(param.getUploadYears());
        }
        criteria.andUsefulEndTimeLessThan(new Date());
        List<FileUpload> dataList = fileUploadMapper.selectByExample(example);
        if (CollectionUtils.isNotEmpty(dataList)) {
            CloseableHttpClient httpClient = null;
            for (FileUpload data : dataList) {
                try {
                    httpClient = HttpClients.createDefault();
                    HttpGet httpGet = new HttpGet(upload_query_url + "/" + data.getResourceKey());
                    HttpResponse httpResponse = httpClient.execute(httpGet);
                    JSONObject resultDto = JSON.parseObject(IOUtils.toString(httpResponse.getEntity().getContent(), "UTF-8"));
                    if (HTTP_SUCCESS_CODE.equals(resultDto.getString("status_code"))) {
                        assemblyModel(resultDto, data);
                        fileUploadMapper.updateByPrimaryKey(data);
                    }
                } catch (Exception e) {
                    logger.error("uploadFile query error.", e);
                } finally {
                    if (null != httpClient) {
                        try {
                            httpClient.close();
                        } catch (IOException e) {
                            logger.error("close httpClient error.", e);
                        }
                    }
                }
            }
        }
    }

    public Boolean delData(String uid){
        boolean delFlag = false;
        FileUploadExample example = new FileUploadExample();
        example.createCriteria().andUidEqualTo(uid);
        List<FileUpload> dataList = fileUploadMapper.selectByExample(example);
        if(CollectionUtils.isNotEmpty(dataList)){
            CloseableHttpClient httpClient = null;
            FileUploadLog uploadLog = new FileUploadLog();
            uploadLog.setRequestId(dataList.get(0).getResourceKey());
            uploadLog.setRequestUrl(upload_query_url + "/" + dataList.get(0).getResourceKey());
            uploadLog.setUid(CommonUtils.getUUID());
            uploadLog.setFileUploadId(dataList.get(0).getUid());
            try {
                httpClient = HttpClients.createDefault();
                HttpDelete httpGet = new HttpDelete(upload_query_url + "/" + dataList.get(0).getResourceKey());
                HttpResponse httpResponse = httpClient.execute(httpGet);
                JSONObject resultDto = JSON.parseObject(IOUtils.toString(httpResponse.getEntity().getContent(), "UTF-8"));
                if (HTTP_SUCCESS_CODE.equals(resultDto.getString("status_code"))) {
                    fileUploadMapper.deleteByPrimaryKey(uid);
                    delFlag = true;
                }
                uploadLog.setResponsJson(resultDto.toJSONString());
                fileUploadLogMapper.insert(uploadLog);
            } catch (Exception e) {
                uploadLog.setResponsJson(e.getMessage());
                fileUploadLogMapper.insert(uploadLog);
                logger.error("uploadFile query error.", e);
            } finally {
                if (null != httpClient) {
                    try {
                        httpClient.close();
                    } catch (IOException e) {
                        logger.error("close httpClient error.", e);
                    }
                }
            }
        }
        return delFlag;
    }
}