package digital.laboratory.platform.entrustment.controller;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.file.FileNameUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.amazonaws.services.s3.model.AmazonS3Exception;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import digital.laboratory.platform.common.core.constant.OSSDirectoryConstants;
import digital.laboratory.platform.common.core.util.R;
import digital.laboratory.platform.common.core.util.TestUtils;
import digital.laboratory.platform.common.log.annotation.SysLog;
import digital.laboratory.platform.common.mybatis.security.service.DLPUser;
import digital.laboratory.platform.common.oss.service.OssFile;
import digital.laboratory.platform.entrustment.entity.CaseEvent;
import digital.laboratory.platform.entrustment.entity.CaseEvidence;
import digital.laboratory.platform.entrustment.service.CaseEventService;
import digital.laboratory.platform.entrustment.service.CaseEvidenceService;
import digital.laboratory.platform.entrustment.vo.CaseEventVO;
import org.springframework.security.access.prepost.PreAuthorize;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.activation.MimetypesFileTypeMap;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.math.BigDecimal;
import java.security.Principal;
import java.time.LocalDateTime;
import java.util.*;


/**
 * 与案件相关的物证信息
 *
 * @author Zhang Xiaolong created at  2022-03-22
 * @describe 案件的物证管理 前端控制器
 */
@RestController
@RequiredArgsConstructor
@RequestMapping("/papp/entrustment/case_evidence" )
@Api( tags = "002-案件的物证管理")
public class CaseEvidenceController {
	private final CaseEventService caseEventService;
    private final  CaseEvidenceService caseEvidenceService;
	private final OssFile ossFile;

	/**
	 * 通过id查询与案件相关的物证信息
	 * @param id id
	 * @return R
	 */
	@ApiOperation(value = "通过id查询", notes = "通过id查询")
	@GetMapping("/{id}" )
	@PreAuthorize("@pms.hasAnyPermission('CaseEvidenceGet')" )
	public R<CaseEvidence> getById(@PathVariable("id" ) String id) {
		return R.ok(caseEvidenceService.getById(id));
	}

	/**
     * 分页查询
     * @param page 分页对象
     * @param caseEvidence 与案件相关的物证信息
     * @return
     */
    @ApiOperation(value = "分页查询", notes = "分页查询")
    @GetMapping("/page" )
    @PreAuthorize("@pms.hasAnyPermission('CaseEvidenceList')" )
    public R getCaseEvidencePage(Page page, CaseEvidence caseEvidence) {
        return R.ok(caseEvidenceService.page(page, Wrappers.query(caseEvidence)));
    }

	/**
	 * 查询案件的物证数量
	 * @param caseId 案件id
	 * @return
	 */
	@ApiOperation(value = "查询案件的物证数量", notes = "查询案件的物证数量")
	@GetMapping("/count" )
	@PreAuthorize("@pms.hasAnyPermission('CaseEvidenceList')" )
	public R getCaseEvidenceCount(String caseId) {
		long count = caseEvidenceService.countByCaseId(caseId);
		Map<String, Long> ret = new HashMap<String, Long>();
		ret.put("count", count);
		return R.ok(count, "查询案件的物证数量成功");
	}

	@GetMapping("/list" )
	@PreAuthorize("@pms.hasAnyPermission('CaseEvidenceList')" )
	public R getCaseEvidenceList(String caseId, String caseNo) {
		if (StringUtils.isNotBlank(caseNo))
		{
			CaseEvent cj = caseEventService.getByCaseNo(caseNo);
			if (cj != null)
			{
				caseId = cj.getId();
			}
			else
			{
				System.out.println(String.format("提供的 caseNo=%s 没有查找到对应的 caseId", caseNo));
				return R.ok(String.format("提供的 caseNo=%s 没有查找到对应的 caseId", caseNo));
			}
		}
		System.out.println(String.format("getCaseEvidenceList, caseNo=%s, caseId=%s", caseNo, caseId));
		if (StringUtils.isNotEmpty(caseId))
		{
			return R.ok(caseEvidenceService.list(Wrappers.<CaseEvidence>query()
					.eq("case_id", caseId)
					.orderByDesc("create_time")
			));
		}
		else {
			return R.ok("caseId 为空");
		}
	}


    /**
     * 新增与案件相关的物证信息
     * @param caseEvidence 与案件相关的物证信息
     * @return R
     */
    @ApiOperation(value = "新增与案件相关的物证信息", notes = "新增与案件相关的物证信息")
    @SysLog("新增与案件相关的物证信息" )
    @PostMapping
    @PreAuthorize("@pms.hasAnyPermission('CaseEvidenceCreate')" )
    public R postAddObject(@RequestBody CaseEvidence caseEvidence) {
		if (StrUtil.isBlank(caseEvidence.getCaseId())) {
			return R.failed(caseEvidence, "物证必须与某个案件关联, 必须提供 caseId");
		}

	    CaseEvent cj = caseEventService.getById(caseEvidence.getCaseId());
		if (cj == null) {
			throw new RuntimeException(String.format("不存在 id 为 %s 的案件", caseEvidence.getCaseId()));
		}
	    if (StrUtil.isBlank(cj.getCaseNo())) {
		    throw new RuntimeException(String.format("对应的案件资料不完整, 不存在案件编号。请先完善案件资料"));
	    }

	    caseEvidence.setId(IdWorker.get32UUID().toUpperCase());
		if (StrUtil.isBlank(caseEvidence.getEvidenceNo())) {
			caseEvidence.setEvidenceNo(caseEvidenceService.getNewEvidenceCode(cj.getCaseNo()));
		}
	    if (caseEvidenceService.save(caseEvidence)) {
		    return R.ok(caseEvidence, "新增物证成功");
	    }
	    else {
		    return R.failed(caseEvidence, "新增物证失败");
	    }
    }

    /**
     * 修改与案件相关的物证信息
     * @param caseEvidence 与案件相关的物证信息
     * @return R
     */
    @ApiOperation(value = "修改与案件相关的物证信息", notes = "修改与案件相关的物证信息")
    @SysLog("修改与案件相关的物证信息" )
    @PutMapping
    @PreAuthorize("@pms.hasAnyPermission('CaseEvidenceEdit')" )
    public R putUpdateById(@RequestBody CaseEvidence caseEvidence, HttpServletRequest theHttpServletRequest) {
	    Principal principal = theHttpServletRequest.getUserPrincipal();
	    DLPUser dlpUser = (DLPUser) ((OAuth2Authentication) principal).getUserAuthentication().getPrincipal();

	    if (StrUtil.isBlank(caseEvidence.getId())) {
		    return R.failed(caseEvidence, "物证信息中没有物证标识 id");
	    }

	    if (StrUtil.isBlank(caseEvidence.getCaseId())) {
		    return R.failed(caseEvidence, "物证必须与某个案件关联, 必须提供 caseId");
	    }

	    CaseEvent cj = caseEventService.getById(caseEvidence.getCaseId());
	    if (cj == null) {
		    throw new RuntimeException(String.format("不存在 id 为 %s 的案件", caseEvidence.getCaseId()));
	    }
	    if (StrUtil.isBlank(cj.getCaseNo())) {
		    throw new RuntimeException(String.format("对应的案件资料不完整, 不存在案件编号。请先完善案件资料"));
	    }
	    if (StrUtil.isBlank(caseEvidence.getEvidenceNo())) {
		    caseEvidence.setEvidenceNo(caseEvidenceService.getNewEvidenceCode(cj.getCaseNo()));
	    }

	    caseEvidence.setCreateBy(null);
	    caseEvidence.setCreateTime(null);
	    caseEvidence.setUpdateBy(dlpUser.getId());
	    caseEvidence.setUpdateTime(LocalDateTime.now());

	    if (caseEvidenceService.updateById(caseEvidence)) {
		    return R.ok(caseEvidence, "保存物证信息成功");
	    }
	    else {
		    return R.failed(caseEvidence, "保存物证信息失败");
	    }
    }

    /**
     * 通过id删除与案件相关的物证信息
     * @param id id
     * @return R
     */
    @ApiOperation(value = "通过id删除与案件相关的物证信息", notes = "通过id删除与案件相关的物证信息")
    @SysLog("通过id删除与案件相关的物证信息" )
    @DeleteMapping("/{id}" )
    @PreAuthorize("@pms.hasAnyPermission('CaseEvidenceDelete')" )
    public R deleteById(@PathVariable String id) {
	    if (StrUtil.isBlank(id)) {
		    return R.failed("必须把物证 id 作为路径的一部分提供!");
	    }
	    CaseEvidence evidence = caseEvidenceService.getById(id);
		if (evidence == null) {
			return R.failed(String.format("不存在 id 为 %s 的物证", id));
		}

	    List<String> attList = ossFile.fileList(OSSDirectoryConstants.CASE_DIRECTORY + "/"+ evidence.getCaseId() + "/" + id);

	    long attCount = attList.size();
	    if (attCount>0) {
		    return R.failed(String.format("这个物证下有 %d 个附件, 必须先删除全部附件后才能删除物证!", attCount));
	    }

	    if (caseEvidenceService.removeById(id)) {
		    return R.ok(evidence, "物证删除成功");
	    }
	    else {
		    return R.failed(evidence, "物证删除失败");
	    }

    }


	/**
	 * 取指定物证的附件列表
	 * @param evidenceId
	 * @return
	 */
	@GetMapping("/attachment/{evidenceId}/list" )
	@PreAuthorize("@pms.hasAnyPermission('CaseEvidenceAttachmentList')" )
	public R getAttachmentList(@PathVariable("evidenceId") String evidenceId) {
		CaseEvidence ce = caseEvidenceService.getById(evidenceId);
		if (ce != null) {
			return R.ok(ossFile.fileList(OSSDirectoryConstants.CASE_DIRECTORY + "/"+ ce.getCaseId() + "/" + evidenceId));
		}
		return R.failed("不存在这个物证");
	}

	/**
	 * 取指定物证的指定附件
	 * @param evidenceId
	 * @param fileName
	 * @param httpServletResponse
	 * @throws Exception
	 */
	@GetMapping("/attachment/{evidenceId}/{fileName}" )
	@PreAuthorize("@pms.hasAnyPermission('CaseEvidenceAttachmentDownload')" )
	public void getAttachmentObj(@PathVariable("evidenceId") String evidenceId, @PathVariable String fileName, HttpServletResponse httpServletResponse) throws Exception {
		CaseEvidence ce = caseEvidenceService.getById(evidenceId);
		if (ce != null) {
			try {
				ossFile.fileGet(OSSDirectoryConstants.CASE_DIRECTORY + "/" + ce.getCaseId() + "/" + evidenceId + "/" + fileName, httpServletResponse.getOutputStream());
				httpServletResponse.setContentType(new MimetypesFileTypeMap().getContentType(fileName));
			} catch (AmazonS3Exception s3e) {
				httpServletResponse.sendError(s3e.getStatusCode(), s3e.toString());
			} catch (Exception e) {
				httpServletResponse.sendError(501, e.toString());
			}
		}
		else {
			httpServletResponse.sendError(404, "不存在这个物证");
		}
	}

	@PostMapping(value = "/attachment/{evidenceId}" )
	@PreAuthorize("@pms.hasAnyPermission('CaseEvidenceAttachmentUpload')" )
	public R uploadAttachmentObj(@PathVariable("evidenceId") String evidenceId, @RequestPart("file") MultipartFile file) throws Exception {
		CaseEvidence ce = caseEvidenceService.getById(evidenceId);
		if (ce != null) {
			System.out.println(String.format("uploadPhotoObj: caseId=%s evidenceId=%s OriginalFilename=%s", ce.getCaseId(), evidenceId, file.getOriginalFilename()));
			String path = OSSDirectoryConstants.CASE_DIRECTORY + "/" + ce.getCaseId() + "/" + evidenceId;
			boolean r = ossFile.fileUpload(file, path);
			Map<String, String> ResultData = new HashMap<>();
			ResultData.put("fileName", FileNameUtil.getName(file.getOriginalFilename()));
			ResultData.put("path", path);
			if (r) {
				return R.ok(ResultData, "上传成功");
			}
			return R.failed("上传失败");
		}
		return R.failed("不存在这个物证");
	}


	@PostMapping(value = "/attachment_base64/{evidenceId}" )
	@PreAuthorize("@pms.hasAnyPermission('CaseEvidenceAttachmentUpload')" )
	public R uploadAttachmentObj_Base64(@PathVariable("evidenceId") String evidenceId, @RequestBody JSONObject jsonParam) throws Exception {
		CaseEvidence ce = caseEvidenceService.getById(evidenceId);
		if (ce != null) {
			System.out.println(String.format("uploadPhotoObj: caseId=%s evidenceId=%s jsonParam.size()=%d", ce.getCaseId(), evidenceId, jsonParam.size()));

			String image = jsonParam.getString("image");
//			System.out.println(String.format("image=%s", image));
			if (StringUtils.isNotEmpty(image)) {
				try {
					String suffix = image.substring(11, image.indexOf(";"));
					String fileName = DateUtil.format(new Date(), "yyyyMMddHHmmss") + "." + suffix;
					System.out.println(String.format("fileName=[%s]", fileName));

					//去掉头信息
					String imgBase64 = image.substring(image.indexOf(",") + 1);
					byte[] decoded = org.apache.commons.codec.binary.Base64.decodeBase64(imgBase64);
					InputStream is = new ByteArrayInputStream(decoded);

					String path = OSSDirectoryConstants.CASE_DIRECTORY + "/" + ce.getCaseId() + "/" + evidenceId ;

					Map<String, String> ResultData = new HashMap<>();
					ResultData.put("fileName", fileName);
					ResultData.put("path", path);

					boolean r = ossFile.fileSave(path+ "/" + fileName, is);
					if (r) {
						return R.ok(ResultData, "上传成功");
					}
					return R.failed("上传失败");

				} catch (Exception e) {
					e.printStackTrace();
					return R.failed("上传失败");
				}
			}
			else {
				return R.failed("上传的数据中没有图像");
			}

		}
		else {
			return R.failed("不存在这个物证");
		}

	}

	@DeleteMapping("/attachment/{evidenceId}/{fileName}" )
	@PreAuthorize("@pms.hasAnyPermission('CaseEvidenceAttachmentDelete')" )
	public R deleteAttachmentObj(@PathVariable("evidenceId") String evidenceId, @PathVariable String fileName) throws Exception {
		CaseEvidence ce = caseEvidenceService.getById(evidenceId);
		if (ce != null) {
			ossFile.fileDelete(OSSDirectoryConstants.CASE_DIRECTORY + "/"+ ce.getCaseId() + "/" + evidenceId + "/" + fileName);
			Map<String, String> ResultData = new HashMap<>();
			ResultData.put("fileName", fileName);
			return R.ok(ResultData, "删除文件成功");
		}
		return R.failed("不存在这个物证");
	}




	//=====================================================================================
	// 测试, 为现有的案件创建一些物证
	@GetMapping("/create100" )
	public R xxx_TestCreate100() {
		List<CaseEventVO> cjs = caseEventService.getCaseVoList(null, null, null, null);
		for (CaseEvent cj : cjs) {
			int num = RandomUtil.randomInt(1, 100);
			for (int i = 0; i < num; i++) {
				List<CaseEvidence> ces = caseEvidenceService.list(Wrappers.<CaseEvidence>query()
						.eq("case_id", cj.getId()));

				if (ces.size()>= num) {
					break;
				}
				CaseEvidence ce = new CaseEvidence();
				
				ce.setId(IdWorker.get32UUID().toUpperCase());
				ce.setCaseId(cj.getId());
				ce.setEvidenceNo(caseEvidenceService.getNewEvidenceCode(cj.getCaseNo()));
				ce.setName(cj.getCaseName()+" 的第 "+i+"个物证");
				ce.setType(RandomUtil.randomEle(new String[]{"非生物性物证", "生物特性物证"}));
				ce.setFieldLabelNo(String.format("现场标牌 %d 号", RandomUtil.randomInt(1, 200)));
				ce.setSource(RandomUtil.randomEle(new String[]{"非生物性物证", "生物特性物证"}));
				ce.setForm(RandomUtil.randomEle(new String[]{"液体", "粉末", "颗粒物"}));

				ce.setQuantity(BigDecimal.valueOf(Math.round(100*RandomUtil.randomDouble(1, 10))/100.0));
				ce.setColor(RandomUtil.randomEle(new String[]{"红色", "绿色", "蓝色", "紫色", "白色", "黑色", "咖啡色"}));
				ce.setUnit(RandomUtil.randomEle(new String[]{"克", "毫克", "升", "毫升", "微升", "块", "颗"}));
				ce.setPersonName(TestUtils.genPersonName());
				ce.setPersonCert(RandomUtil.randomEle(new String[]{"身份证", "警官证", "军官证", "士兵证", "护照"}));
				ce.setPersonId(RandomUtil.randomNumbers(18));
				//ce.setPersonGender(RandomUtil.randomEle(new String[]{"男", "女", "不明性别"}));
				ce.setPersonGender(RandomUtil.randomInt(0, 2));
				ce.setPersonAge(RandomUtil.randomInt(16, 80));
				ce.setPersonAddress(RandomUtil.randomString(12));
				ce.setPersonNationality(RandomUtil.randomEle(new String[]{"中国", "美国", "英国", "法国", "日本"}));
				ce.setPersonNation(RandomUtil.randomInt(1, 20));
				ce.setPack(RandomUtil.randomEle(new String[]{"纸袋", "纸盒", "散装", "塑料盒"}));
				ce.setDescription(
						ce.getName()+", "
						+ce.getPack()+"包装,"
						+"内含 "+ce.getColor()+ce.getForm()
						+" "+ce.getQuantity()+" "+ce.getUnit()
				);

				if (caseEvidenceService.save(ce)) {
					System.out.println("新增物证成功");
				}
				else {
					System.out.println("新增物证失败");
				}

			}
		}
		return R.ok("已经为每个案件创建了 100 个物证");
	}

}
