package org.springblade.dataextraction.controller;

import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;
import java.nio.file.Files;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.List;

import javax.servlet.http.HttpServletResponse;

import org.apache.commons.io.IOUtils;
import org.springblade.core.boot.ctrl.BladeController;
import org.springblade.core.secure.BladeUser;
import org.springblade.core.tool.api.R;
import org.springblade.core.tool.support.Kv;
import org.springblade.dataextraction.enity.DimBelongto;
import org.springblade.dataextraction.enity.DimCType;
import org.springblade.dataextraction.enity.DimCTypeSmall;
import org.springblade.dataextraction.enity.DimProductCategory;
import org.springblade.dataextraction.enity.FctSelectedUser;
import org.springblade.dataextraction.enity.FinOrderFetchTask;
import org.springblade.dataextraction.enity.VFctFetchedOrdersHz;
import org.springblade.dataextraction.kit.ResultSegment;
import org.springblade.dataextraction.kit.TextReader;
import org.springblade.dataextraction.params.FinOrderFetchTaskParams;
import org.springblade.dataextraction.params.TaskParam;
import org.springblade.dataextraction.params.TaskResultParam;
import org.springblade.dataextraction.service.DimBelongtoService;
import org.springblade.dataextraction.service.DimCTypeService;
import org.springblade.dataextraction.service.DimProductCategoryService;
import org.springblade.dataextraction.service.EtlProvinceAreaService;
import org.springblade.dataextraction.service.FctSelectedUserService;
import org.springblade.dataextraction.service.FinOrderFetchTaskService;
import org.springblade.dataextraction.service.VFctFetchedOrdersHzService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;

import cn.hutool.core.util.PhoneUtil;
import cn.hutool.core.util.StrUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import oracle.sql.BFILE;

/**
 * 数据提取接口
 * 
 * @author william
 *
 */
@SuppressWarnings("deprecation")
@Slf4j
@RestController
@RequestMapping("/extraction/task")
@Api(tags = "数据提取", value = "DataExtraction")
public class DataExtractionController extends BladeController {

	@Autowired
	private FctSelectedUserService phoneService;

	@Autowired
	private FinOrderFetchTaskService taskService;

	@Autowired
	private TextReader textReader;

	@Autowired
	private DimCTypeService ctypeService;

	@Autowired
	private DimProductCategoryService productService;

	@Autowired
	private DimBelongtoService channelService;

	@Autowired
	private EtlProvinceAreaService areaService;

	@Autowired
	private VFctFetchedOrdersHzService retService;

	@ApiOperation(value = "任务列表")
	@RequestMapping(value = "/page", method = RequestMethod.POST)
	public ResultSegment page(@RequestBody TaskParam params) throws ParseException {
		QueryWrapper<FinOrderFetchTask> wrapper = new QueryWrapper<>();
		String sysUserName = getUser().getNickName();
		wrapper.eq("CREATOR", sysUserName);
		wrapper.orderByDesc("TASKID");
		wrapper.like(StrUtil.isNotEmpty(params.getMcomment()), "MCOMMENT", params.getMcomment());
		if (params.getStartTime() != null) {
			String time = params.getStartTime() + " 00:00:00";
			wrapper.apply("CREATETIME >= to_date('" + time + "','yyyy-mm-dd hh24:mi:ss')");
		}

		if (params.getEndTime() != null) {
			String time = params.getEndTime() + " 00:00:00";
			wrapper.apply("CREATETIME <= to_date('" + time + "','yyyy-mm-dd hh24:mi:ss')");
		}

		wrapper.apply("MCOMMENT is not null");

		Page<FinOrderFetchTask> page = new Page<>(params.getPageNo(), params.getPageSize());
		Page<FinOrderFetchTask> tp = taskService.page(page, wrapper);
		ResultSegment ret = new ResultSegment(true, 200, "请求成功", tp);
		return ret;
	}

	@ApiOperation(value = "分页查询任务数据结果")
	@RequestMapping(value = "/page/result", method = RequestMethod.POST)
	public ResultSegment taskResult(@RequestBody TaskResultParam params) throws ParseException {
		QueryWrapper<VFctFetchedOrdersHz> wrapper = new QueryWrapper<>();
		String sysUserName = getUser().getNickName();
		wrapper.eq("CREATOR", sysUserName);
		wrapper.eq("TASKID", params.getTaskId());
		wrapper.orderByDesc("TASKID");
		Page<VFctFetchedOrdersHz> page = new Page<>(params.getPageNo(), params.getPageSize());
		Page<VFctFetchedOrdersHz> tp = retService.page(page, wrapper);
		ResultSegment ret = new ResultSegment(true, 200, "请求成功", tp);
		return ret;
	}

	@ApiOperation(value = "添加任务")
	@RequestMapping(value = "/add", method = RequestMethod.POST)
	@ResponseBody
	public R<Object> add(FinOrderFetchTaskParams param) {
		if (param == null) {
			return R.fail("参数为空");
		}

		BladeUser user = getUser();
		if (user == null) {
			return R.fail("没有权限");
		}
		String sysUserName = getUser().getNickName();

		boolean isOk = false;

		FinOrderFetchTask task = param.convert();
		int taskId = taskService.nextTaskId();
		task.setTaskId(taskId);
		task.setCreator(sysUserName);

		// 1-输入单个手机号码；2-导入批量手机号码；3-条件筛选
		int type = task.getUtype();
//		if (type == 1 || type == 2) {
//			// 用户范围为“单手机号输入”、“批量号码导入”两种之一时，创建任务时需要增加“自订购以来”标记字段
//			if (param.getSinceOrder() == 1) {
//				// 选中了自订购以来
//				if (param.getMonthEndForSincet() == null || param.getMonthEndForSincet() == null) {
//					return R.fail("缺少附加数据月份范围");
//				}
//			}
//		}

		if (type == 1 || type == 3) {
			if (type == 1 && StrUtil.isBlank(task.getUserId())) {
				return R.fail("缺少手机号");
			}

			if (type == 3) {

				// 1：订购；2：退订；3：有效
				int userType = task.getCUsertype();
				if (userType == 1) {
					if (task.getOrderDayStart() == null || task.getOrderDayEnd() == null) {
						return R.fail("缺少订购日期");
					}
				} else if (userType == 2) {
					if (task.getCancelDayStart() == null || task.getCancelDayEnd() == null) {
						return R.fail("缺少退订日期");
					}
				} else {
					if (task.getCVmonth() == null) {
						return R.fail("缺少有效期月份");
					}
				}

				if (task.getOrderDayStart() != null && task.getOrderDayEnd() != null && task.getCancelDayStart() != null
						&& task.getCancelDayEnd() != null) {
					return R.fail("订购日期和退订日期不能同时传递");
				}
			}
			isOk = taskService.save(task);
		} else {
			MultipartFile file = task.getFile();
			if (file == null) {
				return R.fail("请上传手机号文件");
			}

			String fileName = file.getOriginalFilename();
			if (!fileName.endsWith(".txt")) {
				return R.fail("文件格式错误");
			}

			task.setTaskId(taskId);
			isOk = batch(task, file);
		}

		if (isOk) {
			startTask(task.getTaskId());
		}

		return isOk ? R.data(taskId, "创建成功") : R.fail("创建失败");
	}

	private boolean batch(FinOrderFetchTask task, MultipartFile file) {
		boolean flag = false;
		try {
			List<FctSelectedUser> userList = new ArrayList<>();
			List<String> list = textReader.read(file.getInputStream());
			if (list != null && !list.isEmpty()) {
				// 批量插入手机号
				for (String userId : list) {
					if (PhoneUtil.isMobile(userId)) {
						FctSelectedUser user = new FctSelectedUser();
						user.setTaskId(task.getTaskId());
						user.setUserId(userId);
						userList.add(user);
					}
				}
			} else {
				log.info("DataExtraction:reader txt error,the userid is null");
			}

			if (userList != null && !userList.isEmpty()) {
				phoneService.createSlice(task.getTaskId());
				flag = phoneService.saveBatch(userList);
				if (flag) {
					flag = taskService.save(task);
				}
			}
		} catch (IOException e) {
			e.printStackTrace();
			log.info("DataExtraction:reader txt error,the exception is:" + e.toString());
		}

		return flag;
	}

	private void startTask(int taskId) {
		new Thread() {
			@Override
			public void run() {
				taskService.startTask(taskId);
			}
		}.start();
	}

	@ApiOperation(value = "任务详情")
	@RequestMapping(value = "/details/{taskId}", method = RequestMethod.GET)
	public R<FinOrderFetchTask> details(@PathVariable(value = "taskId", required = true) Integer taskId) {
		if (taskId == null) {
			return R.fail("任务ID不能为空");
		}
		FinOrderFetchTask task = taskService.get(taskId);
		if (task == null) {
			return R.fail("任务不存在");
		}

		task.setOrderType(task.getCUsertype());
		return R.data(task);
	}

	@ApiOperation(value = "数据文件下载")
	@RequestMapping(value = "/download/{taskId}", method = RequestMethod.GET)
	public void download(@PathVariable(value = "taskId", required = true) Integer taskId,
			HttpServletResponse response) {
		BladeUser user = getUser();
		if (user == null) {
			throw new RuntimeException("DataExtraction:download no auth");
		}

		FinOrderFetchTask task = taskService.get(taskId);
		if (task == null) {
			log.info("DataExtraction:download task is not exist");
			throw new RuntimeException("DataExtraction:download task is not exist");
		}
		try {
			BFILE bf = (BFILE) taskService.getFile(taskId);
			if (bf != null && bf.fileExists()) {
				bf.openFile();
				InputStream is = bf.getBinaryStream();
				if (is != null) {
					response.setContentType("application/vnd.ms-excel");
					response.setCharacterEncoding("utf-8");
					String comment = task.getMcomment();
					comment = StrUtil.isBlank(comment) ? String.valueOf(taskId) : comment;
//					String name = bf.getName();
//					name = StrUtil.isBlank(name) ? comment : name;
					String fileName = URLEncoder.encode(comment, "UTF-8");
					response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".csv");

					byte[] buffer = new byte[10240];
					BufferedInputStream bufferedInputStream = new BufferedInputStream(is);
					int len;
					while ((len = bufferedInputStream.read(buffer)) != -1) {
						response.getOutputStream().write(buffer, 0, len);
					}
//					response.getOutputStream().write(IOUtils.toByteArray(is));
					response.getOutputStream().flush();
					response.getOutputStream().close();
					bufferedInputStream.close();
					buffer.clone();
				} else {
					log.info("bfile inputstream is null");
				}
			}
		} catch (Exception e) {
			log.info("DataExtraction:download error, the exception is:" + e.toString());
			e.printStackTrace();
		}
	}

	@ApiOperation(value = "产品大类")
	@RequestMapping(value = "/cate/big", method = RequestMethod.GET)
	public R<List<DimCType>> cateBig() {
		List<DimCType> list = ctypeService.listBigCate();
		return R.data(list);
	}

	@ApiOperation(value = "产品小类")
	@RequestMapping(value = "/cate/small", method = RequestMethod.GET)
	public R<List<DimCTypeSmall>> cateSmall(String cptype) {
		List<DimCTypeSmall> list = productService.listSmallCate(cptype);
		return R.data(list);
	}

	@ApiOperation(value = "产品列表")
	@RequestMapping(value = "/products", method = RequestMethod.GET)
	public R<List<DimProductCategory>> products(String fullCptype) {
		List<DimProductCategory> list = productService.listProduct(fullCptype);
		return R.data(list);
	}

	@ApiOperation(value = "产品树结构")
	@RequestMapping(value = "/productTree", method = RequestMethod.GET)
	public R<List<Kv>> productTree() {
		List<Kv> dataList = new ArrayList<>();
		List<DimCType> bigList = ctypeService.listBigCate();
		if (bigList != null) {
			for (int i = 0, size = bigList.size(); i < size; i++) {
				Kv parent = Kv.create();
				parent.put("id", String.valueOf(i + 100));
				parent.put("pid", String.valueOf(0));
				DimCType big = bigList.get(i);
				parent.put("name", big.getCategoryName());
				parent.put("value", big.getCptype());
				parent.put("type", "big");

				List<DimCTypeSmall> smallList = productService.listSmallCate(big.getCptype());
				if (smallList != null) {
					List<Kv> children = new ArrayList<>();
					for (int j = 0, count = smallList.size(); j < count; j++) {
						Kv child = Kv.create();
						child.put("id", String.valueOf(j + 200));
						child.put("pid", parent.get("id"));
						DimCTypeSmall small = smallList.get(j);
						child.put("name", small.getCategoryName2());
						child.put("value", small.getFullCptype());
						child.put("type", "small");
						children.add(child);

						List<DimProductCategory> productList = productService.listProduct(small.getFullCptype());
						if (productList != null) {
							List<Kv> sunList = new ArrayList<>();
							for (int k = 0, num = productList.size(); k < num; k++) {
								Kv sun = Kv.create();
								sun.put("id", String.valueOf(k + 300));
								sun.put("pid", child.get("id"));
								DimProductCategory product = productList.get(k);
								sun.put("name", product.getShortName());
								sun.put("value", product.getSpid());
								sun.put("type", "product");
								sunList.add(sun);
							}
							child.put("children", sunList);
						}
					}
					parent.put("children", children);
				}
				dataList.add(parent);
			}
		}

		return R.data(dataList);
	}

	@ApiOperation(value = "渠道分类")
	@RequestMapping(value = "/channels", method = RequestMethod.GET)
	public R<List<DimBelongto>> channels(String taskId) {
		List<DimBelongto> list = channelService.list();
		return R.data(list);
	}

	@ApiOperation(value = "省份列表")
	@RequestMapping(value = "/provinces", method = RequestMethod.GET)
	public R<List<String>> provinces() {
		List<String> list = areaService.provinces();
		return R.data(list);
	}

	@ApiOperation("城市列表")
	@RequestMapping(value = "/citys", method = RequestMethod.GET)
	public R<Object> citys(String province) {
		List<String> list = areaService.citys(province);
		return R.data(list);
	}

	@ApiOperation("区域树形结构")
	@RequestMapping(value = "/areaTree", method = RequestMethod.GET)
	public R<List<Kv>> areaTree() {
		List<Kv> dataList = new ArrayList<>();
		List<String> provinceList = areaService.provinces();
		if (provinceList != null) {
			for (int i = 0, size = provinceList.size(); i < size; i++) {
				Kv parent = Kv.create();
				parent.put("id", String.valueOf(i + 100));
				parent.put("pid", String.valueOf(0));
				String province = provinceList.get(i);
				parent.put("name", province);
				parent.put("type", "province");

				List<Kv> children = new ArrayList<>();
				List<String> cityList = areaService.citys(province);
				for (int j = 0, count = cityList.size(); j < count; j++) {
					Kv child = Kv.create();
					child.put("id", String.valueOf(j + 200));
					child.put("pid", parent.get("id"));
					String city = cityList.get(j);
					child.put("name", city);
					child.put("type", "city");
					children.add(child);
				}
				parent.put("children", children);
				dataList.add(parent);
			}
		}
		return R.data(dataList);
	}

	@ApiOperation("更新任务名称")
	@RequestMapping(value = "/update/name", method = RequestMethod.POST)
	public R<Object> updateTaskName(Integer taskId, String taskName, String conditionJson) {
		if (taskId == null) {
			return R.fail("任务ID不能为空");
		}
		FinOrderFetchTask task = taskService.get(taskId);
		if (task == null) {
			return R.fail("任务不存在");
		}

		LambdaUpdateWrapper<FinOrderFetchTask> wrapper = Wrappers.<FinOrderFetchTask>lambdaUpdate();
		wrapper.eq(FinOrderFetchTask::getTaskId, taskId);
		wrapper.set(FinOrderFetchTask::getMcomment, taskName);
		if (StrUtil.isNotBlank(conditionJson)) {
			wrapper.set(FinOrderFetchTask::getConditionJson, conditionJson);
		}
		boolean flag = taskService.update(wrapper);
		if (flag) {
			task.setMcomment(taskName);
			task.setConditionJson(conditionJson);
		}
		return flag ? R.data(task) : R.fail("操作失败");
	}

	@ApiOperation(value = "批量导入号码最大限制数")
	@RequestMapping(value = "/maxrows/import", method = RequestMethod.GET)
	public R<Integer> getMaxRowsImport() {
		return R.data(taskService.getMaxRowsImport());
	}
}
