package com.quinn.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.quinn.common.QuinnConstant;
import com.quinn.common.SourceType;
import com.quinn.mapper.SourceCategoryMapper;
import com.quinn.pojo.Source;
import com.quinn.mapper.SourceMapper;
import com.quinn.pojo.SourceCategory;
import com.quinn.pojo.SourceWithStar;
import com.quinn.service.SourceService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.quinn.utils.*;
import com.quinn.vo.MyPageParam;
import com.quinn.vo.QuerySource;
import com.quinn.vo.SourceUpdateForm;
import com.quinn.vo.SourceWriteForm;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Date;
import java.util.List;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author limqsh
 * @since 2022-05-03
 */
@Service
public class SourceServiceImpl extends ServiceImpl<SourceMapper, Source> implements SourceService {

    @Resource
    OSSClientUtil ossClientUtil;
    @Resource
    RedisUtils redisUtils;
    @Resource
    SourceCategoryMapper sourceCategoryMapper;
    @Resource
    SourceMapper sourceMapper;

    @Override
    public void downloadSource(HttpServletResponse response, Source source,String sessionId) throws IOException {
        String sourceLink = source.getSourceLink();
        addDownLoadRecord(source,sessionId);
        // 读取文件内容。
        BufferedInputStream in = new BufferedInputStream(ossClientUtil.downloadFile(sourceLink));
        BufferedOutputStream out = new BufferedOutputStream(response.getOutputStream());
        byte[] buffer = new byte[1024];
        int lenght = 0;
        while ((lenght = in.read(buffer)) != -1) {
            out.write(buffer, 0, lenght);
        }
        if (out != null) {
            out.flush();
            out.close();
        }
        if (in != null) {
            in.close();
        }
    }

    @Override
    public void downloadForBaidu(HttpServletResponse response, Source source,String sessionId) throws IOException {
        addDownLoadRecord(source,sessionId);
        PrintWriter writer = response.getWriter();
        writer.write(source.getSourceLink());
        writer.flush();
        writer.close();
    }

    @Override
    public Source view(String sid,String sessionId) {
        Source source = getOne(new QueryWrapper<Source>().eq("sid", sid));
        addDownLoadRecord(source,sessionId);
        return source;
    }

    @Override
    public void uploadNewSource(MultipartFile file, SourceWriteForm sourceWriteForm) throws IOException {
        // 先进行文件上传成功再落地
        String fileType = "";
        String fileLink = sourceWriteForm.getSourceLink();
        if (file != null && !file.isEmpty() && SourceType.OSS.name().equals(sourceWriteForm.getSourceType())){
            String originalFilename = file.getOriginalFilename();
            fileType = originalFilename.substring(originalFilename.lastIndexOf(QuinnConstant.LINK_SUFFIX)).toLowerCase();
            fileLink = ossClientUtil.uploadFile(QuinnUtils.getUuid() + QuinnConstant.LINK_DATE_STR
                    + QuinnUtils.getStrFromDate(new Date()), file.getInputStream());
        }
        // 构建问题对象
        Source source = new Source();
        source.setSid(QuinnUtils.getUuid());
        source.setEnName(sourceWriteForm.getEnName());
        source.setFileType(fileType);
        source.setSourceName(sourceWriteForm.getTitle());
        source.setDetail(CovertEmojStr.coverStr(sourceWriteForm.getSubContent()));
        source.setSourceContent(sourceWriteForm.getContent());
        String s = ContentUtil.toTextContentFromWangEdit(CovertEmojStr.coverStr(sourceWriteForm.getContentJson()));
        sourceWriteForm.setContentJson(s);
        source.setSourceType(sourceWriteForm.getSourceType());
        source.setSourceLink(fileLink);

        // 类型
        source.setCategoryId(sourceWriteForm.getCategoryId());
        SourceCategory category = sourceCategoryMapper.selectById(sourceWriteForm.getCategoryId());
        source.setCategoryName(category.getCategory());
        source.setDownRecord(0);
        source.setGmtCreate(QuinnUtils.getTime());
        source.setGmtUpdate(QuinnUtils.getTime());
        // 存储对象
        save(source);
    }

    @Override
    public void updateSource(MultipartFile file, SourceUpdateForm sourceUpdateForm) throws IOException {
        Source before = getOne(new QueryWrapper<Source>().eq("sid",sourceUpdateForm.getSid()));
        String fileType = before.getFileType();
        // 先进行文件上传成功再落地
        String fileLink = before.getSourceLink();
        if (file != null && !file.isEmpty() && SourceType.OSS.name().equals(sourceUpdateForm.getSourceType())){
            // 上传了新文件，需要删除之前的文件
            ossClientUtil.deleteFile(before.getSourceLink());
            String originalFilename = file.getOriginalFilename();
            fileType = originalFilename.substring(originalFilename.lastIndexOf(QuinnConstant.LINK_SUFFIX)).toLowerCase();
            fileLink = ossClientUtil.uploadFile(QuinnUtils.getUuid() + QuinnConstant.LINK_DATE_STR
                    + QuinnUtils.getStrFromDate(new Date()), file.getInputStream());
        }else if (!SourceType.OSS.name().equals(sourceUpdateForm.getSourceType()) && !StringUtils.isEmpty(sourceUpdateForm.getSourceLink())){
            fileLink = sourceUpdateForm.getSourceLink();
        }
        before.setEnName(sourceUpdateForm.getEnName());
        before.setFileType(fileType);
        before.setSourceName(sourceUpdateForm.getSourceName());
        before.setDetail(sourceUpdateForm.getDetail());
        before.setSourceContent(CovertEmojStr.coverStr(sourceUpdateForm.getSourceContent()));
        String s = ContentUtil.toTextContentFromWangEdit(CovertEmojStr.coverStr(sourceUpdateForm.getContentJson()));
        before.setContentJson(s);
        before.setSourceType(sourceUpdateForm.getSourceType());
        before.setSourceLink(fileLink);

        // 类型
        before.setCategoryId(sourceUpdateForm.getCategoryId());
        SourceCategory category = sourceCategoryMapper.selectById(sourceUpdateForm.getCategoryId());
        before.setCategoryName(category.getCategory());
        before.setGmtUpdate(QuinnUtils.getTime());
        updateById(before);
    }

    @Override
    public void deleteSource(String sid) {
        Source before = getOne(new QueryWrapper<Source>().eq("sid",sid));
        if (SourceType.OSS.name().equals(before.getSourceType())){
            // 上传了新文件，需要删除之前的文件
            ossClientUtil.deleteFile(before.getSourceLink());
        }
        removeById(before);
    }

    @Override
    public List<SourceWithStar> listPageStar(QuerySource querySource, MyPageParam myPageParam) {
        QueryWrapper<Source> sourceQuery = new QueryWrapper<>();
        int allCount = count(sourceQuery);
        myPageParam.setAllTotal(allCount);
        addParam(sourceQuery,querySource.getName(),querySource.getCategory());
        int count = count(sourceQuery);
        myPageParam.setTotal(count);
        return sourceMapper.listPageStar(querySource,myPageParam);
    }


    private void addParam(QueryWrapper<Source> sourceQuery, String name, int category) {
        if (!StringUtils.isEmpty(name)){
            sourceQuery.like("source_name",name);
        }
        if (category > 0){
            sourceQuery.eq("category_id",category);
        }
    }

    /**
     * 更新热度
     * @param source
     */
    private void addDownLoadRecord(Source source,String sessionId) {
        /** 使用redis记录访问量可以降低数据库压力,但是时效性就会降低，
        * 需要不断跑批处理，用户量小或者单实例不推荐这么做
         * 我们此处是为了实现session级别不能恶意刷热度
        */
        String value = redisUtils.get(sessionId + source.getSid());
        if (!QuinnConstant.SESSION_VIEW_KEY.equals(value)){
            source.setDownRecord(source.getDownRecord() + 1);
            redisUtils.set(sessionId + source.getSid(),QuinnConstant.SESSION_VIEW_KEY,QuinnConstant.SESSION_TIME_OUT);
            updateById(source);
        }
    }

}
