package org.springblade.material.controller;


import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.springblade.core.mp.support.Condition;
import org.springblade.core.mp.support.Query;
import org.springblade.core.secure.utils.SecureUtil;
import org.springblade.core.tool.api.R;
import org.springblade.material.entity.BladeMaterial;
import org.springblade.material.entity.BladeMaterialCategory;
import org.springblade.material.service.IBladeMaterialCategoryService;
import org.springblade.material.service.IBladeMaterialService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.*;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;

/**
 * <p>
 * 素材表 前端控制器
 * </p>
 *
 * @author zbc
 * @since 2022-03-02
 */
@RestController
@RequestMapping("/material")
@Api(value = "素材管理", tags = "素材接口")
@Slf4j
public class BladeMaterialController {

	@Autowired
	private IBladeMaterialService bladeMaterialService;

	@Autowired
	private IBladeMaterialCategoryService bladeMaterialCategoryService;

	@Value("${blade.material.uploadPath}")
	private String materialUploadPath;

	@Value("${blade.material.domain}")
	private String materialUrl;

	@Value("${datasource.type}")
	private String dbType;

	@PostMapping("/uploadMaterial")
	public R uploadFile(MultipartFile file, String categoryCode) {
		if (null == file) {
			return R.fail("文件不能为空");
		}
		if(StrUtil.isEmpty(categoryCode)){
			return R.fail("参数异常");
		}
		String oFileName = file.getOriginalFilename();
		String fileSuffix = oFileName.substring(oFileName.lastIndexOf("."));
//		System.out.println("uploadMaterial = " + oFileName);
		if (!".jpg".equalsIgnoreCase(fileSuffix) &&
				!".jpeg".equalsIgnoreCase(fileSuffix) &&
				!".gif".equalsIgnoreCase(fileSuffix) &&
				!".png".equalsIgnoreCase(fileSuffix) &&
				!".mp3".equalsIgnoreCase(fileSuffix) &&
				!".mp4".equalsIgnoreCase(fileSuffix)
		) {
			return R.fail("只能上传jpg/jpeg/gif/png/mp3/mp4类型的文件");
		}

		if (file.getSize() > 1024 * 1000 * 100) {
			return R.fail("附件不得大于100M");
		}

		String tempFileName = UUID.randomUUID().toString() + fileSuffix;

		File f = new File(materialUploadPath+categoryCode+"/"+tempFileName);
		try {
			FileUtils.copyInputStreamToFile(file.getInputStream(), f);
		} catch (IOException e) {
			e.printStackTrace();
		}
		Map<String, Object> map = new HashMap<>();
		map.put("materialName",tempFileName);
		map.put("path",categoryCode+"/"+tempFileName);
		map.put("originalName",oFileName);
		return R.data(map);
	}


	@PostMapping("/save")
	@ApiOperation(value = "新增素材")
	public R save(@Valid @RequestBody BladeMaterial material) {
		Long userId = SecureUtil.getUserId();
		material.setCreateTime(new Date());
		material.setCreateUser(userId);
		return R.status(bladeMaterialService.save(material));
	}

	@GetMapping("/page")
	@ApiOperation(value = "素材列表")
	public R<IPage<BladeMaterial>> page(Long categoryId,Integer materialType,Query query) {
		if(categoryId == null){
			return R.fail("分类ID不能为空");
		}
		BladeMaterialCategory category = bladeMaterialCategoryService.getById(categoryId);
		if(category == null){
			return R.fail("分类不存在");
		}
		IPage<BladeMaterial> pages = null;
		if(materialType != null){
			//materialType 1 图片 2 音频 3 视频
			if(materialType == 1){
				IPage<BladeMaterial> page = Condition.getPage(query);
				if ("mysql".equals(dbType)) {
					pages = bladeMaterialService.page(page, new LambdaQueryWrapper<BladeMaterial>()
							.eq(BladeMaterial::getCategoryId, categoryId)
							.apply("SUBSTRING_INDEX(material_name,'.',-1) != 'mp4'" + "" + " AND SUBSTRING_INDEX(material_name,'.',-1) != 'mp3'")
							.orderByDesc(BladeMaterial::getCreateTime)
					);
				} else if ("kingbase".equals(dbType)) {
					pages = bladeMaterialService.page(page, new LambdaQueryWrapper<BladeMaterial>()
							.eq(BladeMaterial::getCategoryId, categoryId)
							.apply("SPLIT_PART(material_name,'.',2) != 'mp4'" + "" + " AND SPLIT_PART(material_name,'.',2) != 'mp3'")
							.orderByDesc(BladeMaterial::getCreateTime)
					);
				}

				List<BladeMaterial> records = pages.getRecords();
				for (BladeMaterial record : records) {
					String path = record.getPath();
					record.setBase64Str(imgToBase64(path));
				}
			}
			if(materialType == 2){
				IPage<BladeMaterial> page = Condition.getPage(query);
				if ("mysql".equals(dbType)) {
					pages = bladeMaterialService.page(page, new LambdaQueryWrapper<BladeMaterial>()
							.eq(BladeMaterial::getCategoryId, categoryId)
							.apply("SUBSTRING_INDEX(material_name,'.',-1) = 'mp3'")
							.orderByDesc(BladeMaterial::getCreateTime)
					);
				} else if ("kingbase".equals(dbType)) {
					pages = bladeMaterialService.page(page, new LambdaQueryWrapper<BladeMaterial>()
							.eq(BladeMaterial::getCategoryId, categoryId)
							.apply("SPLIT_PART(material_name,'.',2) = 'mp3'")
							.orderByDesc(BladeMaterial::getCreateTime)
					);
				}
			}
			if(materialType == 3){
				IPage<BladeMaterial> page = Condition.getPage(query);
				if ("mysql".equals(dbType)) {
					pages = bladeMaterialService.page(page, new LambdaQueryWrapper<BladeMaterial>()
							.eq(BladeMaterial::getCategoryId, categoryId)
							.apply("SUBSTRING_INDEX(material_name,'.',-1) = 'mp4'")
							.orderByDesc(BladeMaterial::getCreateTime)
					);
				} else if ("kingbase".equals(dbType)) {
					pages = bladeMaterialService.page(page, new LambdaQueryWrapper<BladeMaterial>()
							.eq(BladeMaterial::getCategoryId, categoryId)
							.apply("SPLIT_PART(material_name,'.',2) = 'mp4'")
							.orderByDesc(BladeMaterial::getCreateTime)
					);
				}
			}
		}else {
			IPage<BladeMaterial> page = Condition.getPage(query);
			pages = bladeMaterialService.page(page,new LambdaQueryWrapper<BladeMaterial>()
					.eq(BladeMaterial::getCategoryId,categoryId)
					.orderByDesc(BladeMaterial::getCreateTime)
			);

			List<BladeMaterial> records = pages.getRecords();
			for (BladeMaterial record : records) {
				String path = record.getPath();
				record.setBase64Str(imgToBase64(path));
			}
		}
		return R.data(pages);
	}

	private String imgToBase64(String path) {
		log.info("imgToBase64 === path : {}", path);
		byte[] data = null;
		try {
			//new一个URL对象
			URL url = new URL(materialUrl+path);
			//打开链接
			HttpURLConnection conn = (HttpURLConnection) url.openConnection();
			//设置请求方式为"GET"
			conn.setRequestMethod("GET");
			//超时响应时间为5秒
			conn.setConnectTimeout(5 * 1000);
			//通过输入流获取图片数据
			InputStream inStream = conn.getInputStream();
			data = new byte[inStream.available()];
			inStream.read(data);
			inStream.close();
			String encode = Base64.getEncoder().encodeToString(data);
			log.info("encode = "+ StringUtils.isBlank(encode));
			return encode;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return "";
	}


	@GetMapping("/generateZip")
	@ApiOperation(value = "获取指定用户下的所有素材生成zip文件")
	public R generateZip(HttpServletResponse response) throws Exception {
		// 选择要压缩的文件夹
		Long userId = SecureUtil.getUserId();
		log.info("userId = {}",userId);
		List<BladeMaterial> materialList = bladeMaterialService.list(new LambdaQueryWrapper<BladeMaterial>()
				.eq(BladeMaterial::getCreateUser, userId)
		);
		//获取个人所传的所有素材分类id
		Set<Long> collectSet = materialList.stream().map(BladeMaterial::getCategoryId).collect(Collectors.toSet());

		List<BladeMaterialCategory> materialCategoryList = bladeMaterialCategoryService.list(new LambdaQueryWrapper<BladeMaterialCategory>()
				.in(BladeMaterialCategory::getId, collectSet)
		);
		List<String> collect = materialCategoryList.stream().map(BladeMaterialCategory::getCategoryCode).collect(Collectors.toList());
		String[] directoriesToZip = collect.toArray(new String[collect.size()]);

		//String fileName = "archive.zip";
		//设置文件下载名称
		//response.setHeader("Content-disposition", "attachment;filename=\"" + new String(fileName.getBytes(),"iso-8859-1") + "\"");//如果有中文需要转码
		//用于浏览器下载响应
		//OutputStream out = null;
		// 选择要压缩的文件夹
		//String[] directoriesToZip = {"account", "lm9cj20230201164716"};
		//ByteArrayOutputStream bos = new ByteArrayOutputStream();
		//ZipOutputStream zipOut = new ZipOutputStream(bos);

		//输出zip文件地址
		String outputFilePath = materialUploadPath+"archive.zip";
		//String outputFilePath = "D:/zip/archive.zip";
		// 创建ZipOutputStream
		FileOutputStream fos = new FileOutputStream(outputFilePath);
		ZipOutputStream zipOut = new ZipOutputStream(fos);
		// 递归压缩文件夹
		for (String s : directoriesToZip) {
			File fileToZip = new File(materialUploadPath + s);
			zipFolder(fileToZip, zipOut);
		}
		zipOut.close();
		fos.close();
		return R.success("ok");
	}

	private void zipFolder(File folder,  ZipOutputStream zipOut) throws IOException {
		String bassPath = materialUploadPath.replace("/",File.separator);
		// 如果是一个文件夹，则递归压缩其中的文件
		if (folder.isDirectory()) {
			for (File file : folder.listFiles()) {
				zipFolder(file,zipOut);
			}
		}
		// 如果是一个文件，则将其添加到zip文件中
		else {
			String path = folder.getPath().replace(bassPath,"");
			FileInputStream fis = new FileInputStream(folder);
			String name = folder.getName();
			//String path = folder.getPath().replace(bassPath,"");
			log.info("path = {}",path);
			ZipEntry zipEntry = new ZipEntry(folder.getPath().replace(bassPath,""));
			zipOut.putNextEntry(zipEntry);
			byte[] bytes = new byte[1024];
			int length;
			while ((length = fis.read(bytes)) >= 0) {
				zipOut.write(bytes, 0, length);
			}
			fis.close();
		}
	}



	@PostMapping("/uploadZip")
	@ApiOperation(value = "上传素材zip压缩文件")
	public R unzip(@RequestParam("file") MultipartFile file) throws IOException {
		String zipFilePath = materialUploadPath.replace("/",File.separator);
		File zipFile = new File(zipFilePath);
		// 创建解压缩目录
		if (!zipFile.exists()) {
			zipFile.mkdirs();
		}
		ZipInputStream zipInputStream = new ZipInputStream(new BufferedInputStream(file.getInputStream()));
		ZipEntry zipEntry;
		byte[] buffer = new byte[1024];
		while ((zipEntry = zipInputStream.getNextEntry()) != null) {
			String filePath = zipFilePath + zipEntry.getName();
			log.info("filePath = {}",filePath);
			if (!zipEntry.isDirectory()) {
				// 创建目录，防止出现不存在的目录
				File parentDir = new File(filePath).getParentFile();
				if (!parentDir.exists()) {
					parentDir.mkdirs();
				}
				// 解压文件
				FileOutputStream fos = new FileOutputStream(filePath);
				BufferedOutputStream bos = new BufferedOutputStream(fos, buffer.length);
				int len;
				while ((len = zipInputStream.read(buffer, 0, buffer.length)) != -1) {
					bos.write(buffer, 0, len);
				}
				bos.flush();
				bos.close();
			}
			zipInputStream.closeEntry();
		}
		zipInputStream.close();
		return R.success("ok");
	}


}

