package com.jeequan.jeepay.agent.ctrl.store;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.jeequan.jeepay.agent.ctrl.CommonCtrl;
import com.jeequan.jeepay.core.aop.MethodLog;
import com.jeequan.jeepay.core.constants.ApiCodeEnum;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.core.entity.MchInfo;
import com.jeequan.jeepay.core.exception.BizException;
import com.jeequan.jeepay.core.interfaces.device.IPrinterService;
import com.jeequan.jeepay.core.interfaces.device.ISpeakerService;
import com.jeequan.jeepay.core.model.ApiRes;
import com.jeequan.jeepay.core.model.device.PayOrderInfo4Device;
import com.jeequan.jeepay.core.utils.DateKit;
import com.jeequan.jeepay.core.utils.SpringBeansUtil;
import com.jeequan.jeepay.db.entity.*;
import com.jeequan.jeepay.service.impl.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;

import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 设备厂商配置管理类
 *
 * @author zx
 *
 * @date 2021-12-28 09:15
 */
@Slf4j
@RestController
@RequestMapping("api/store/device")
public class MchStoreDeviceController extends CommonCtrl {

	@Autowired private DeviceProvideConfigService deviceProvideConfigService;
	@Autowired private MchStoreDeviceService mchStoreDeviceService;
	@Autowired private MchStoreService mchStoreService;
	@Autowired private MchAppService mchAppService;
	@Autowired private MchQrcDeviceRelaService mchQrcDeviceRelaService;

	/**
	 * @author: zx
	 * @date: 2021-12-28 09:15
	 * @describe: 门店设备列表
	 */
	@PreAuthorize("hasAnyAuthority('ENT_DEVICE_SPEAKER_DEVICE_LIST', 'ENT_DEVICE_PRINTER_DEVICE_LIST', 'ENT_DEVICE_POS_DEVICE_LIST', " +
			"'ENT_DEVICE_PLUGIN_CDKEY_LIST', 'ENT_DEVICE_FACE_APP_LIST')")
	@GetMapping
	public ApiRes pages() {

		MchStoreDevice mchStoreDevice = getObject(MchStoreDevice.class);

		// 可查看自己和全部下级代理的设备
		String currentAgentNo = getCurrentAgentNo();
		List<String> subAgentNoList = agentInfoService.queryAllSubAgentNo(currentAgentNo);
		if (CollectionUtil.isNotEmpty(subAgentNoList)) {
			mchStoreDevice.setSubAgentNoList(subAgentNoList);
		}

		IPage<MchStoreDevice> page = mchStoreDeviceService.selectPage(getIPage(), mchStoreDevice);
		if (page.getTotal() == 0) {
			return ApiRes.page(page);
		}
		// 列表添加是否属于自身，设备只能绑定直属商户，app端展示隐藏也使用此字段
		for (MchStoreDevice device: page.getRecords()) {
			if (currentAgentNo.equals(device.getAgentNo())) {
				device.addExt("isSelf", true);
			}
		}

		//返回数据
		return ApiRes.page(page);
	}

	/**
	 * @author: zx
	 * @date: 2021-12-28 09:15
	 * @describe: 门店设备修改
	 */
	@PreAuthorize("hasAnyAuthority('ENT_DEVICE_SPEAKER_DEVICE_EDIT', 'ENT_DEVICE_PRINTER_DEVICE_EDIT', 'ENT_DEVICE_POS_DEVICE_EDIT', " +
			"'ENT_DEVICE_PLUGIN_CDKEY_EDIT', 'ENT_DEVICE_FACE_APP_EDIT')")
	@MethodLog(remark = "设备厂商配置修改")
	@PutMapping("/{deviceId}")
	public ApiRes update(@PathVariable("deviceId") Long deviceId) {
		MchStoreDevice mchStoreDevice = getObject(MchStoreDevice.class);
		mchStoreDevice.setDeviceId(deviceId);
		mchStoreDevice.setBatchId(null);
		mchStoreDevice.setDeviceNo(null);
		mchStoreDevice.setDeviceParams(null);
		mchStoreDevice.setCreatedAt(null);
		mchStoreDevice.setUpdatedAt(null);

		// 可查看自己和全部下级代理的设备
		List<String> subAgentNoList = agentInfoService.queryAllSubAgentNo(getCurrentAgentNo());
		MchStoreDevice dbRecord = mchStoreDeviceService.getById(deviceId);
		if (!subAgentNoList.contains(dbRecord.getAgentNo())) {
			return ApiRes.fail(ApiCodeEnum.SYS_PERMISSION_ERROR);
		}

		boolean result = mchStoreDeviceService.updateById(mchStoreDevice);
		if(!result) {
			throw new BizException(ApiCodeEnum.SYS_OPERATION_FAIL_UPDATE);
		}

		return ApiRes.ok();
	}

	/**
	 * @author: zx
	 * @date: 2021-12-28 09:15
	 * @describe: 根据ID获取门店设备
	 */
	@PreAuthorize("hasAnyAuthority('ENT_DEVICE_SPEAKER_DEVICE_VIEW', 'ENT_DEVICE_PRINTER_DEVICE_VIEW', 'ENT_DEVICE_POS_DEVICE_VIEW', " +
			"'ENT_DEVICE_PLUGIN_CDKEY_VIEW', 'ENT_DEVICE_FACE_APP_VIEW')")
	@GetMapping("/{deviceId}")
	public ApiRes get(@PathVariable("deviceId") Long deviceId) {
		// 可查看自己和全部下级代理的设备
		List<String> subAgentNoList = agentInfoService.queryAllSubAgentNo(getCurrentAgentNo());
		MchStoreDevice dbRecord = mchStoreDeviceService.getById(deviceId);
		if (!subAgentNoList.contains(dbRecord.getAgentNo())) {
			return ApiRes.fail(ApiCodeEnum.SYS_PERMISSION_ERROR);
		}

		// 设备是否属于自身
		if (getCurrentAgentNo().equals(dbRecord.getAgentNo())) {
			dbRecord.addExt("isSelf", true);
		}

		// 添加服务商、商户、门店名称
		AgentInfo allotAgent = agentInfoService.getById(dbRecord.getAgentNo());
		if (allotAgent != null) {
			dbRecord.addExt("agentName", allotAgent.getAgentName());
		}
		if (dbRecord.getBindState() == CS.YES) {
			if (StringUtils.isNotBlank(dbRecord.getMchNo())) {
				MchInfo mchInfo = mchInfoService.getById(dbRecord.getMchNo());
				if (mchInfo != null) {
					dbRecord.addExt("mchName", mchInfo.getMchName());
				}
			}

			if (StringUtils.isNotBlank(dbRecord.getAppId())) {
				MchAppEntity mchAppEntity = mchAppService.getById(dbRecord.getAppId());
				if (mchAppEntity != null) {
					dbRecord.addExt("appName", mchAppEntity.getAppName());
				}
			}

			if (dbRecord.getStoreId() != null) {
				MchStore mchStore = mchStoreService.getById(dbRecord.getStoreId());
				if (mchStore != null) {
					dbRecord.addExt("storeName", mchStore.getStoreName());
				}
			}
		}

		List<MchQrcDeviceRela> relaList = mchQrcDeviceRelaService.list(MchQrcDeviceRela.gw().eq(MchQrcDeviceRela::getDeviceId, deviceId));
		if (!CollectionUtils.isEmpty(relaList)) {
			dbRecord.addExt("qrcIdList", relaList.stream().map(MchQrcDeviceRela::getQrcId).collect(Collectors.toList()));
		}

		return ApiRes.ok(dbRecord);
	}

	/**
	 * @author: zx
	 * @date: 2021-12-28 09:15
	 * @describe: 播报测试
	 */
	@PreAuthorize("hasAnyAuthority('ENT_DEVICE_SPEAKER_DEVICE_TEST')")
	@PostMapping("/speak/{deviceId}")
	public ApiRes speak(@PathVariable("deviceId") Long deviceId) {

		Long amountL = getRequiredAmountL("amount");

		// 可查看自己和全部下级代理的设备
		List<String> subAgentNoList = agentInfoService.queryAllSubAgentNo(getCurrentAgentNo());

		MchStoreDevice mchStoreDevice = mchStoreDeviceService.getById(deviceId);
		if (mchStoreDevice == null || mchStoreDevice.getState() != CS.YES || !subAgentNoList.contains(mchStoreDevice.getAgentNo())) {
			return ApiRes.customFail("设备不存在或已禁用");
		}

		DeviceProvideConfig provideConfig = deviceProvideConfigService.getById(mchStoreDevice.getConfigId());
		if (provideConfig == null || provideConfig.getState() != CS.YES) {
			return ApiRes.customFail("设备厂商未配置或已禁用");
		}

		// 设备类型
		String provider = mchStoreDevice.getProvider();
		ISpeakerService speakerService = SpringBeansUtil.getBean(provider + "SpeakerService", ISpeakerService.class);

		// 设备参数
		JSONObject deviceParams = new JSONObject();
		deviceParams.put("deviceParams", mchStoreDevice.getDeviceParams());
		deviceParams.put("bizConfigParams", mchStoreDevice.getBizConfigParams());
		deviceParams.put("providerParams", provideConfig.getProviderParams());

		// 消息内容
		PayOrderInfo4Device speakPayOrderInfo = new PayOrderInfo4Device();
		speakPayOrderInfo.setAmount(amountL);
		speakPayOrderInfo.setWayCodeType(CS.PAY_WAY_CODE_TYPE.WECHAT);
		speakPayOrderInfo.setPayOrderId(String.valueOf(DateKit.currentTimeMillis()));

		try {
			speakerService.send(deviceParams, speakPayOrderInfo);
			return ApiRes.ok();
		}catch (BizException e) {
			throw e;
		}
	}

	/**
	 * @author: zx
	 * @date: 2021-12-28 09:15
	 * @describe: 打印测试
	 */
	@PreAuthorize("hasAnyAuthority('ENT_DEVICE_PRINTER_DEVICE_TEST')")
	@PostMapping("/print/{deviceId}")
	public ApiRes print(@PathVariable("deviceId") Long deviceId) {

		Long amountL = getRequiredAmountL("amount");

		// 可查看自己和全部下级代理的设备
		List<String> subAgentNoList = agentInfoService.queryAllSubAgentNo(getCurrentAgentNo());

		MchStoreDevice mchStoreDevice = mchStoreDeviceService.getById(deviceId);
		if (mchStoreDevice == null || mchStoreDevice.getState() != CS.YES || !subAgentNoList.contains(mchStoreDevice.getAgentNo())) {
			return ApiRes.customFail("设备不存在或已禁用");
		}

		DeviceProvideConfig provideConfig = deviceProvideConfigService.getById(mchStoreDevice.getConfigId());
		if (provideConfig == null || provideConfig.getState() != CS.YES) {
			return ApiRes.customFail("设备厂商未配置或已禁用");
		}

		// 设备类型
		String provider = mchStoreDevice.getProvider();
		IPrinterService printerService = SpringBeansUtil.getBean(provider + "PrinterService", IPrinterService.class);

		// 设备参数
		JSONObject deviceParams = new JSONObject();
		deviceParams.put("deviceParams", mchStoreDevice.getDeviceParams());
		deviceParams.put("bizConfigParams", mchStoreDevice.getBizConfigParams());
		deviceParams.put("providerParams", provideConfig.getProviderParams());

		// 消息内容
		PayOrderInfo4Device printPayOrderInfo = new PayOrderInfo4Device();
		printPayOrderInfo.setAmount(amountL);
		printPayOrderInfo.setWayCodeType(CS.PAY_WAY_CODE_TYPE.WECHAT);
		printPayOrderInfo.setPayOrderId(String.valueOf(DateKit.currentTimeMillis()));
		printPayOrderInfo.setCreatedAt(DateUtil.date());

		try {
			printerService.send(deviceParams, printPayOrderInfo);
			return ApiRes.ok();
		}catch (BizException e) {
			throw e;
		}
	}

	/**
	 * @author: zx
	 * @date: 2021-12-28 09:15
	 * @describe: 清空打印队列
	 */
	@PreAuthorize("hasAnyAuthority('ENT_DEVICE_PRINTER_DEVICE_CLEAR')")
	@PostMapping("/clear/{deviceId}")
	public ApiRes clear(@PathVariable("deviceId") Long deviceId) {

		MchStoreDevice mchStoreDevice = mchStoreDeviceService.getById(deviceId);
		if (mchStoreDevice == null || mchStoreDevice.getState() != CS.YES) {
			return ApiRes.customFail("设备不存在");
		}

		DeviceProvideConfig provideConfig = deviceProvideConfigService.getById(mchStoreDevice.getConfigId());
		if (provideConfig == null || provideConfig.getState() != CS.YES) {
			return ApiRes.customFail("设备厂商未配置");
		}

		// 设备类型
		String provider = mchStoreDevice.getProvider();
		IPrinterService printerService = SpringBeansUtil.getBean(provider + "PrinterService", IPrinterService.class);

		// 设备参数
		JSONObject deviceParams = new JSONObject();
		deviceParams.put("deviceParams", mchStoreDevice.getDeviceParams());
		deviceParams.put("bizConfigParams", mchStoreDevice.getBizConfigParams());
		deviceParams.put("providerParams", provideConfig.getProviderParams());

		try {
			printerService.clearPrinter(deviceParams);
			return ApiRes.ok();
		}catch (Exception e) {
			return ApiRes.customFail(e.getMessage());
		}
	}

	/**
	 * @author: zx
	 * @date: 2021-12-28 09:15
	 * @describe: 绑定设备
	 */
	@MethodLog(remark = "绑定设备")
	@PreAuthorize("hasAnyAuthority('ENT_DEVICE_SPEAKER_DEVICE_EDIT', 'ENT_DEVICE_PRINTER_DEVICE_EDIT', 'ENT_DEVICE_POS_DEVICE_EDIT'," +
			"'ENT_DEVICE_PLUGIN_CDKEY_EDIT', 'ENT_DEVICE_FACE_APP_EDIT')")
	@PutMapping("/bind/{deviceId}")
	public ApiRes bind(@PathVariable("deviceId") Long deviceId) {

		String mchNo = getValStringRequired("mchNo");
		String storeId = getValStringRequired("storeId");
		Byte bindType = getValByte("bindType");

		MchInfo mchInfo = mchInfoService.getById(mchNo);
		if (mchInfo == null || StringUtils.isBlank(mchInfo.getAgentNo()) || !mchInfo.getAgentNo().equals(getCurrentAgentNo())) {
			throw new BizException("商户不存在");
		}

		MchStoreDevice dbRecord = mchStoreDeviceService.getById(deviceId);
		if (dbRecord == null || StringUtils.isBlank(dbRecord.getAgentNo()) || !dbRecord.getAgentNo().equals(getCurrentAgentNo())) {
			throw new BizException(ApiCodeEnum.SYS_OPERATION_FAIL_SEARCH);
		}

		// 除云喇叭和云打印外的设备  需绑定商户应用
		String appId = "";
		if (dbRecord.getDeviceType() != MchStoreDevice.DEVICE_TYPE_SPEAKER && dbRecord.getDeviceType() != MchStoreDevice.DEVICE_TYPE_PRINTER) {
			appId = getValStringRequired("appId");
		}

		MchStoreDevice updateRecord = new MchStoreDevice();
		updateRecord.setDeviceId(deviceId).setMchNo(mchNo).setAppId(appId).setStoreId(storeId).setBindState(CS.YES);
		if (null != bindType) {
			updateRecord.setBindType(bindType);
		}

		// 云喇叭  同步绑定码牌
		if (dbRecord.getDeviceType() == MchStoreDevice.DEVICE_TYPE_SPEAKER) {

			String qrcIdListStr = getValString("qrcIdList");

			// 云喇叭绑定类型 为码牌时，需传入绑定的码牌id
			List<Long> qrcList = new LinkedList<>();
			if (null != bindType && bindType == MchStoreDevice.DEVICE_BIND_TYPE_QRC && StringUtils.isNotBlank(qrcIdListStr)) {
				qrcList = JSONArray.parseArray(qrcIdListStr, Long.class);
			}

			boolean result = mchStoreDeviceService.bindSpeakerDevice(updateRecord, dbRecord.getBindQrcId(), qrcList);
			if (!result) {
				return ApiRes.customFail("绑定失败");
			}
			return ApiRes.ok();
		}

		// 云打印、扫码pos执行更新
		if (mchStoreDeviceService.updateById(updateRecord)) {
			return ApiRes.ok();
		}

		return ApiRes.customFail("绑定失败");
	}

	/**
	 * @author: zx
	 * @date: 2021-12-28 09:15
	 * @describe: 解绑设备
	 */
	@MethodLog(remark = "解绑设备")
	@PreAuthorize("hasAnyAuthority('ENT_DEVICE_SPEAKER_DEVICE_EDIT', 'ENT_DEVICE_PRINTER_DEVICE_EDIT', 'ENT_DEVICE_POS_DEVICE_EDIT'," +
			" 'ENT_DEVICE_PLUGIN_CDKEY_EDIT', 'ENT_DEVICE_FACE_APP_EDIT')")
	@PostMapping("/unbind/{deviceId}")
	public ApiRes unbind(@PathVariable("deviceId") Long deviceId) {

		MchStoreDevice dbRecord = mchStoreDeviceService.getById(deviceId);
		if (dbRecord == null || dbRecord.getBindState() == CS.NO || !dbRecord.getAgentNo().equals(getCurrentAgentNo())) {
			return ApiRes.customFail("解绑失败");
		}

		MchInfo mchInfo = mchInfoService.getById(dbRecord.getMchNo());
		if (mchInfo == null || StringUtils.isBlank(mchInfo.getAgentNo()) || !mchInfo.getAgentNo().equals(getCurrentAgentNo())) {
			throw new BizException("当前解绑设备不属于您的直属商户，无法解绑！");
		}

		mchStoreDeviceService.unbind(dbRecord);

		return ApiRes.ok();
	}

	/**
	 * @author: zx
	 * @date: 2021-12-28 09:15
	 * @describe: 划拨/收回设备
	 */
	@MethodLog(remark = "划拨/收回设备")
	@PreAuthorize("hasAnyAuthority('ENT_DEVICE_SPEAKER_DEVICE_ALLOT', 'ENT_DEVICE_PRINTER_DEVICE_ALLOT', " +
			"'ENT_DEVICE_POS_DEVICE_ALLOT', 'ENT_DEVICE_PLUGIN_CDKEY_ALLOT', 'ENT_DEVICE_FACE_APP_ALLOT')")
	@PostMapping("/allotDevice")
	public ApiRes allotDevice() {

		// 服务商是否支持划拨码牌、设备
		SysConfig isSupportAgentAllot = sysConfigService.getById("isSupportAgentAllot");
		if(isSupportAgentAllot == null || String.valueOf(CS.NO).equals(isSupportAgentAllot.getConfigVal())){
			throw  new BizException("不支持服务商划拨码牌、设备");
		}

		String allotType = getValStringRequired("allotType"); // 划拨类型：select-勾选划拨  batch-批次划拨
		String allotOrRecover = getValStringRequired("allotOrRecover"); // 分配类型：allot-划拨  recover-收回

		// 构建批量更新设备ID集合
		List<MchStoreDevice> list;
		if (allotType.equals("select")) {

			String allotDeviceIds = getValStringRequired("allotDeviceIds");
			list = mchStoreDeviceService.list(MchStoreDevice.gw().in(MchStoreDevice::getDeviceId, Arrays.asList(allotDeviceIds.split(","))));

		}else if (allotType.equals("batch")) {

			String batchId = getValStringRequired("batchId");
			list = mchStoreDeviceService.list(MchStoreDevice.gw().eq(MchStoreDevice::getBatchId, batchId));

		}else {
			throw new BizException("划拨类型错误");
		}
		if (CollUtil.isEmpty(list)) {
			throw new BizException("请选择设备");
		}


		// 当前代理只可划拨自己和直接下级代理的设备
		List<String> subAgentNoList = agentInfoService.querySubAgentNo(getCurrentAgentNo());
		for (MchStoreDevice mchStoreDevice: list) {
			if (!subAgentNoList.contains(mchStoreDevice.getAgentNo())) {
				throw new BizException("存在不可划拨设备【设备号：" + mchStoreDevice.getDeviceNo() + "】");
			}
		}

		List<Long> deviceIdList = list.stream().map(MchStoreDevice::getDeviceId).collect(Collectors.toList());

		// 1、收回设备
		if (allotOrRecover.equals("recover")) {
			mchStoreDeviceService.recoverDevice(true, deviceIdList, subAgentNoList, getCurrentAgentNo());
			return ApiRes.ok();
		}

		// 2、划拨设备
		String agentNo = getValStringRequired("agentNo");
		List<String> mchNoList = getMchNoListByAgentNo(agentNo);

		mchStoreDeviceService.allotDevice(true, agentNo, deviceIdList, mchNoList, subAgentNoList);

		return ApiRes.ok();
	}


}
