package com.yiqi.web.controller.common;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.yiqi.common.annotation.Anonymous;
import com.yiqi.common.config.RuoYiConfig;
import com.yiqi.common.constant.Constants;
import com.yiqi.common.core.domain.AjaxResult;
import com.yiqi.common.core.domain.R;
import com.yiqi.common.core.domain.UploadOSSVO;
import com.yiqi.common.core.domain.vo.ExportTableColumnVO;
import com.yiqi.common.exception.ServiceException;
import com.yiqi.common.utils.DateUtils;
import com.yiqi.common.utils.SmsUtils;
import com.yiqi.common.utils.StringUtils;
import com.yiqi.common.utils.file.FileUploadUtils;
import com.yiqi.common.utils.file.FileUtils;
import com.yiqi.common.utils.poi.ExcelUtil;
import com.yiqi.framework.config.ServerConfig;
import com.yiqi.generator.domain.GenTableColumn;
import com.yiqi.generator.mapper.GenTableColumnMapper;
import com.yiqi.oss.cloud.CloudStorageConfig;
import com.yiqi.oss.cloud.OSSFactory;
import com.yiqi.system.domain.SysSms;
import com.yiqi.system.service.ISysSmsService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartRequest;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 通用请求处理
 *
 * @author ruoyi
 */
@Api(tags = "通用接口")
@RestController
@RequestMapping("/common")
public class CommonController {
    private static final Logger log = LoggerFactory.getLogger(CommonController.class);

    @Autowired
    private ServerConfig serverConfig;
    @Autowired
    private GenTableColumnMapper genTableColumnMapper;
    @Autowired
    private ISysSmsService sysSmsService;
    @Autowired
    private RuoYiConfig ruoYiConfig;
    @Autowired
    private CloudStorageConfig cloudStorageConfig;

    private static final String FILE_DELIMETER = ",";

    @ApiOperation("导出库表结构")
    @GetMapping("exportTableColumn")
    public void exportTableColumn(HttpServletResponse response, @RequestParam String tableName) throws Exception {
        List<GenTableColumn> dbTableColumns = genTableColumnMapper.selectDbTableColumnsByName(tableName);
        List<ExportTableColumnVO> list = new ArrayList<>();
        for (GenTableColumn dbTableColumn : dbTableColumns) {
            ExportTableColumnVO exportTableColumnVO = new ExportTableColumnVO();
            exportTableColumnVO.setColumnName(dbTableColumn.getColumnName());
            exportTableColumnVO.setColumnType(dbTableColumn.getColumnType());
            exportTableColumnVO.setIsAutoIncrement(dbTableColumn.getIsIncrement());
            exportTableColumnVO.setIsKey(dbTableColumn.getIsPk());
            exportTableColumnVO.setIsRequire(dbTableColumn.getIsRequired());
            exportTableColumnVO.setRemark(dbTableColumn.getColumnComment());
            list.add(exportTableColumnVO);
        }
        ExcelUtil<ExportTableColumnVO> util = new ExcelUtil<ExportTableColumnVO>(ExportTableColumnVO.class);
        util.exportExcel(response, list, "用户数据");
    }

    /**
     * 通用下载请求
     *
     * @param fileName 文件名称
     * @param delete   是否删除
     */
    @GetMapping("/download")
    public void fileDownload(String fileName, Boolean delete, HttpServletResponse response, HttpServletRequest request) {
        try {
            if (!FileUtils.checkAllowDownload(fileName)) {
                throw new Exception(StringUtils.format("文件名称({})非法，不允许下载。 ", fileName));
            }
            String realFileName = System.currentTimeMillis() + fileName.substring(fileName.indexOf("_") + 1);
            String filePath = RuoYiConfig.getDownloadPath() + fileName;

            response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
            FileUtils.setAttachmentResponseHeader(response, realFileName);
            FileUtils.writeBytes(filePath, response.getOutputStream());
            if (delete) {
                FileUtils.deleteFile(filePath);
            }
        } catch (Exception e) {
            log.error("下载文件失败", e);
        }
    }

    /**
     * 通用上传请求（单个）
     */
    @PostMapping("/upload")
    public AjaxResult uploadFile(MultipartFile file) throws Exception {
        try {
            // 上传文件路径
            String filePath = RuoYiConfig.getUploadPath();
            // 上传并返回新文件名称
            String fileName = FileUploadUtils.upload(filePath, file);
            String url = serverConfig.getUrl() + fileName;
            AjaxResult ajax = AjaxResult.success();
            ajax.put("url", url);
            ajax.put("fileName", fileName);
            ajax.put("newFileName", FileUtils.getName(fileName));
            ajax.put("originalFilename", file.getOriginalFilename());
            return ajax;
        } catch (Exception e) {
            return AjaxResult.error(e.getMessage());
        }
    }

    /**
     * 通用上传请求（多个）
     */
    @PostMapping("/uploads")
    public AjaxResult uploadFiles(List<MultipartFile> files) throws Exception {
        try {
            // 上传文件路径
            String filePath = RuoYiConfig.getUploadPath();
            List<String> urls = new ArrayList<String>();
            List<String> fileNames = new ArrayList<String>();
            List<String> newFileNames = new ArrayList<String>();
            List<String> originalFilenames = new ArrayList<String>();
            for (MultipartFile file : files) {
                // 上传并返回新文件名称
                String fileName = FileUploadUtils.upload(filePath, file);
                String url = serverConfig.getUrl() + fileName;
                urls.add(url);
                fileNames.add(fileName);
                newFileNames.add(FileUtils.getName(fileName));
                originalFilenames.add(file.getOriginalFilename());
            }
            AjaxResult ajax = AjaxResult.success();
            ajax.put("urls", StringUtils.join(urls, FILE_DELIMETER));
            ajax.put("fileNames", StringUtils.join(fileNames, FILE_DELIMETER));
            ajax.put("newFileNames", StringUtils.join(newFileNames, FILE_DELIMETER));
            ajax.put("originalFilenames", StringUtils.join(originalFilenames, FILE_DELIMETER));
            return ajax;
        } catch (Exception e) {
            return AjaxResult.error(e.getMessage());
        }
    }

    @Anonymous
    @ApiOperation("上传文件到腾讯云OSS")
    @PostMapping(value = "uploadOSS")
    public R<UploadOSSVO> uploadOSS(HttpServletRequest request) throws Exception {
        List items = ((MultipartRequest) request).getFiles("file");
        System.out.println("itemsSize:" + items.size());
        List<UploadOSSVO> uploadOSSVOS = new ArrayList<>();

        Iterator itr = items.iterator();
        while (itr.hasNext()) {
            MultipartFile item = (MultipartFile) itr.next();
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM");
            String date = sdf.format(new Date());
            String key = "image/" + date + "/";
            if (!"image".equals(item.getContentType().split("/")[0])) {
                key = "file/" + date + "/";
            }
            String fileName = java.util.UUID.randomUUID().toString().replaceAll("-", "") + "."
                    + item.getOriginalFilename().substring(item.getOriginalFilename().lastIndexOf(".") + 1);
            //上传文件
            String suffix = item.getOriginalFilename().substring(item.getOriginalFilename().lastIndexOf("."));
            String url = OSSFactory.build(cloudStorageConfig).uploadSuffix(item.getBytes(), suffix);
            UploadOSSVO uploadOSSVO = new UploadOSSVO(url, fileName);
            return R.ok(uploadOSSVO);
        }
        return R.fail();
    }

    @Anonymous
    @ApiOperation("wangEditor上传文件到腾讯云OSS")
    @PostMapping(value = "uploadWangOSS")
    public Object uploadWangOSS(HttpServletRequest request) throws Exception {
        List items = ((MultipartRequest) request).getFiles("file");
        System.out.println("itemsSize:" + items.size());
        Map res = new HashMap();
        List<Map> uploadOSSVOS = new ArrayList<>();
        Iterator itr = items.iterator();
        while (itr.hasNext()) {
            MultipartFile item = (MultipartFile) itr.next();
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM");
            String date = sdf.format(new Date());
            String key = "image/" + date + "/";
            if (!"image".equals(item.getContentType().split("/")[0])) {
                key = "file/" + date + "/";
            }
            String fileName = java.util.UUID.randomUUID().toString().replaceAll("-", "") + "."
                    + item.getOriginalFilename().substring(item.getOriginalFilename().lastIndexOf(".") + 1);
            //上传文件
            String suffix = item.getOriginalFilename().substring(item.getOriginalFilename().lastIndexOf("."));
            String url = OSSFactory.build(cloudStorageConfig).uploadSuffix(item.getBytes(), suffix);
            Map<String, String> map = new HashMap<>();
            map.put("url", url);
            map.put("alt", fileName);
            map.put("href", "");
            uploadOSSVOS.add(map);
        }
        res.put("errno", 0);
        res.put("data", uploadOSSVOS);
        return res;
    }


    @Anonymous
    @ApiOperation("wangEditor上传视频文件到腾讯云OSS")
    @PostMapping(value = "uploadWangVideoOSS")
    public Object uploadWangVideoOSS(HttpServletRequest request) throws Exception {
        List items = ((MultipartRequest) request).getFiles("video");
        System.out.println("videoSize:" + items.size());
        Map res = new HashMap();
        Map<String, String> map = new HashMap<>();
        Iterator itr = items.iterator();
        while (itr.hasNext()) {
            MultipartFile item = (MultipartFile) itr.next();
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM");
            String date = sdf.format(new Date());
            String fileName = java.util.UUID.randomUUID().toString().replaceAll("-", "") + "."
                    + item.getOriginalFilename().substring(item.getOriginalFilename().lastIndexOf(".") + 1);
            //上传文件
            String suffix = item.getOriginalFilename().substring(item.getOriginalFilename().lastIndexOf("."));
            String url = OSSFactory.build(cloudStorageConfig).uploadSuffix(item.getBytes(), suffix);
            map.put("url", url);
        }
        res.put("errno", 0);
        res.put("data", map);
        return res;
    }

//    @Anonymous
//    @ApiOperation("上传文件到腾讯云OSS")
//    @PostMapping(value = "uploadOSS")
//    public R<UploadOSSVO> uploadOSS(HttpServletRequest request) throws Exception{
//        List items = ((MultipartRequest)request).getFiles("file");
//        System.out.println("itemsSize:" + items.size());
//        Iterator itr = items.iterator();
//        while (itr.hasNext()) {
//            MultipartFile item = (MultipartFile) itr.next();
//            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM");
//            String date = sdf.format(new Date());
//            String key = "image/" + date + "/";
//            if (!"image".equals(item.getContentType().split("/")[0])) {
//                key = "file/" + date + "/";
//            }
//            String fileName = java.util.UUID.randomUUID().toString().replaceAll("-", "") + "."
//                    + item.getOriginalFilename().substring(item.getOriginalFilename().lastIndexOf(".") + 1);
//            String oldFileName = fileName;
//            ObjectMetadata objectMetadata = new ObjectMetadata();
//            // 上传的流如果能够获取准确的流长度，则推荐一定填写 content-length
//            // 如果确实没办法获取到，则下面这行可以省略，但同时高级接口也没办法使用分块上传了
//            objectMetadata.setContentLength(item.getSize());
//            objectMetadata.setHeader("expires", new Date(System.currentTimeMillis() + 30000L));
//            PutObjectRequest putObjectRequest = new PutObjectRequest(ruoYiConfig.getCosBucket(), key + fileName, item.getInputStream(), objectMetadata);
//            // 添加图片处理规则
//            if ("image".equals(item.getContentType().split("/")[0])) {
//                List<PicOperations.Rule> ruleList = new LinkedList<>();
//                PicOperations picOperations = new PicOperations();
//                picOperations.setIsPicInfo(1);
//                PicOperations.Rule rule = new PicOperations.Rule();
//                rule.setBucket(ruoYiConfig.getCosBucket());
//                fileName = UUID.randomUUID().toString().replaceAll("-", "") + "."
//                        + item.getOriginalFilename().substring(item.getOriginalFilename().lastIndexOf(".") + 1);
//                rule.setFileId("thumb/" + fileName);
//                rule.setRule("imageMogr2/thumbnail/800x800");
//                ruleList.add(rule);
//                picOperations.setRules(ruleList);
//                putObjectRequest.setPicOperations(picOperations);
//            }
//            // 1 初始化用户身份信息（secretId, secretKey）。
//            // SECRETID和SECRETKEY请登录访问管理控制台 https://console.cloud.tencent.com/cam/capi 进行查看和管理
//            String secretId = ruoYiConfig.getCosSecretId();
//            String secretKey = ruoYiConfig.getCosSecretKey();
//            COSCredentials cred = new BasicCOSCredentials(secretId, secretKey);
//            // 2 设置 bucket 的地域, COS 地域的简称请参照 https://cloud.tencent.com/document/product/436/6224
//            // clientConfig 中包含了设置 region, https(默认 http), 超时, 代理等 set 方法, 使用可参见源码或者常见问题 Java SDK 部分。
//            Region region = new Region("ap-shanghai");
//            ClientConfig clientConfig = new ClientConfig(region);
//            // 这里建议设置使用 https 协议
//            // 从 5.6.54 版本开始，默认使用了 https
//            clientConfig.setHttpProtocol(HttpProtocol.https);
//            // 3 生成 cos 客户端。
//            COSClient cosClient = new COSClient(cred, clientConfig);
//            PutObjectResult result = cosClient.putObject(putObjectRequest);
//            UploadOSSVO uploadOSSVO = new UploadOSSVO(ruoYiConfig.getCosBaseUrl() + key + "thumb/" + fileName,fileName);
//            return R.ok(uploadOSSVO);
//        }
//        return R.fail();
//    }


    @Anonymous
    @ApiOperation("base64格式上传文件到腾讯云OSS")
    @PostMapping(value = "uploadBase64OSS")
    public R<UploadOSSVO> uploadBase64OSS(@RequestParam @ApiParam("base64文件") String base64Data) throws Exception {
        String suffix = base64Data.split(";base64,")[0].split("/")[1];
        if ("vnd.openxmlformats-officedocument.wordprocessingml.document".equals(suffix)) {
            suffix = "docx";
        }
        if ("msword".equals(suffix)) {
            suffix = "doc";
        }

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM");
        String date = sdf.format(new Date());
        String key = "image/" + date + "/";
        String fileName = java.util.UUID.randomUUID().toString().replaceAll("-", "") + "."
                + suffix;
//        ObjectMetadata objectMetadata = new ObjectMetadata();
//        // 上传的流如果能够获取准确的流长度，则推荐一定填写 content-length
//        // 如果确实没办法获取到，则下面这行可以省略，但同时高级接口也没办法使用分块上传了
////        objectMetadata.setContentLength(item.getSize());
//        objectMetadata.setHeader("expires", new Date(System.currentTimeMillis() + 30000L));
//        Base64.Decoder decoder = Base64.getDecoder();
//        byte[] imageByte = decoder.decode(base64Data.split(",")[1]);
//        InputStream stream = new ByteArrayInputStream(imageByte);
//        PutObjectRequest putObjectRequest = new PutObjectRequest(ruoYiConfig.getCosBucket(), key + fileName, stream, objectMetadata);
//        // 添加图片处理规则
//        List<PicOperations.Rule> ruleList = new LinkedList<>();
//        PicOperations picOperations = new PicOperations();
//        picOperations.setIsPicInfo(1);
//        PicOperations.Rule rule = new PicOperations.Rule();
//        rule.setBucket(ruoYiConfig.getCosBucket());
//        fileName = UUID.randomUUID().toString().replaceAll("-", "") + "."
//                + suffix;
//        rule.setFileId("thumb/" + fileName);
//        rule.setRule("imageMogr2/thumbnail/800x800");
//        ruleList.add(rule);
//        picOperations.setRules(ruleList);
//        putObjectRequest.setPicOperations(picOperations);
//        // 1 初始化用户身份信息（secretId, secretKey）。
//        // SECRETID和SECRETKEY请登录访问管理控制台 https://console.cloud.tencent.com/cam/capi 进行查看和管理
//        String secretId = ruoYiConfig.getCosSecretId();
//        String secretKey = ruoYiConfig.getCosSecretKey();
//        COSCredentials cred = new BasicCOSCredentials(secretId, secretKey);
//        // 2 设置 bucket 的地域, COS 地域的简称请参照 https://cloud.tencent.com/document/product/436/6224
//        // clientConfig 中包含了设置 region, https(默认 http), 超时, 代理等 set 方法, 使用可参见源码或者常见问题 Java SDK 部分。
//        Region region = new Region("ap-shanghai");
//        ClientConfig clientConfig = new ClientConfig(region);
//        // 这里建议设置使用 https 协议
//        // 从 5.6.54 版本开始，默认使用了 https
//        clientConfig.setHttpProtocol(HttpProtocol.https);
//        // 3 生成 cos 客户端。
//        COSClient cosClient = new COSClient(cred, clientConfig);
//        PutObjectResult result = cosClient.putObject(putObjectRequest);
        UploadOSSVO uploadOSSVO = new UploadOSSVO(ruoYiConfig.getCosBaseUrl() + key + "thumb/" + fileName, fileName);
        return R.ok(uploadOSSVO);
    }

    /**
     * 本地资源通用下载
     */
    @GetMapping("/download/resource")
    public void resourceDownload(String resource, HttpServletRequest request, HttpServletResponse response)
            throws Exception {
        try {
            if (!FileUtils.checkAllowDownload(resource)) {
                throw new Exception(StringUtils.format("资源文件({})非法，不允许下载。 ", resource));
            }
            // 本地资源路径
            String localPath = RuoYiConfig.getProfile();
            // 数据库资源地址
            String downloadPath = localPath + StringUtils.substringAfter(resource, Constants.RESOURCE_PREFIX);
            // 下载名称
            String downloadName = StringUtils.substringAfterLast(downloadPath, "/");
            response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
            FileUtils.setAttachmentResponseHeader(response, downloadName);
            FileUtils.writeBytes(downloadPath, response.getOutputStream());
        } catch (Exception e) {
            log.error("下载文件失败", e);
        }
    }

    @ApiOperation("发送验证码")
    @GetMapping(value = "sendSms")
    public R sendSms(@RequestParam @ApiParam("手机号") String phone, @RequestParam @ApiParam("短信类型，0：注册，1：忘记密码，2修改支付密码") String smsType) throws Exception {
        if (sysSmsService.count(new QueryWrapper<SysSms>().lambda().eq(SysSms::getPhone, phone)
                .ge(SysSms::getCreateTime, DateUtils.parseDate(DateUtils.dateTimeNow("yyyy-MM-dd"), "yyyy-MM-dd"))) > 10) {
            throw new ServiceException("今日短信数量已达上限");
        }

        if (sysSmsService.count(new QueryWrapper<SysSms>().lambda()
                .eq(SysSms::getPhone, phone)
                .eq(SysSms::getSmsType, smsType)
                .gt(SysSms::getCreateTime, new Date(System.currentTimeMillis() - 1000 * 60 * 5))) > 3) {
            throw new ServiceException("您的短信发送过于频繁，请稍后再操作");
        }

        SysSms sysSms = new SysSms();
        sysSms.setPhone(phone);
        sysSms.setCode((Math.random() + "").substring(2, 8));
        sysSms.setSmsType(smsType);
        sysSms.setCreateTime(DateUtils.getNowDate());

        SmsUtils.sendSms(sysSms.getPhone(), "1125637", new String[]{sysSms.getCode(), "5"});
        sysSmsService.save(sysSms);
        return R.ok();
    }
}
