package com.uas.platform.b2b.openapi.controller;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.CompletionService;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.uas.platform.b2b.core.util.DateUtils;
import com.uas.platform.b2b.model.Vendor;
import com.uas.platform.b2b.openapi.model.Cust;
import com.uas.platform.b2b.openapi.model.CustData;
import com.uas.platform.b2b.openapi.model.Forecast;
import com.uas.platform.b2b.openapi.model.IO;
import com.uas.platform.b2b.openapi.model.Sale;
import com.uas.platform.b2b.openapi.model.Stock;
import com.uas.platform.b2b.openapi.service.CustDataService;
import com.uas.platform.b2b.openapi.support.ErrorUtils;
import com.uas.platform.b2b.openapi.support.ICallable;
import com.uas.platform.b2b.openapi.support.ICallableAdapter;
import com.uas.platform.b2b.service.VendorService;
import com.uas.platform.b2b.support.SystemSession;
import com.uas.platform.core.exception.SystemError;

/**
 * 获取我的客户的数据
 * 
 * @author yingp
 * 
 */
@RestController
@RequestMapping("/openapi/custdata")
public class CustDataController {

	@Autowired
	private CustDataService custDataService;

	@Autowired
	private VendorService vendorService;

	private final static String dateFormat = "\\d{4}-\\d{1,2}-\\d{1,2}";

	/**
	 * 取客户信息
	 * 
	 * @return
	 */
	@RequestMapping(params = "type=cust")
	public List<Cust> getCusts() {
		List<Cust> custs = new ArrayList<Cust>();
		List<Vendor> _custs = vendorService.findMyCustomersUsingErp();
		if (!CollectionUtils.isEmpty(_custs)) {
			for (Vendor _cust : _custs) {
                custs.add(new Cust(_cust.getMyEnUU(), _cust.getMyEnterprise().getEnName()));
            }
		}
		return custs;
	}

	/**
	 * 取物料库存信息
	 * 
	 * @param custId
	 *            指定客户企业ID
	 */
	@RequestMapping(params = "type=stock")
	public List<CustData<Stock>> getProductStockInfo(Long custId) {
		final String brands = SystemSession.getUser().getEnterprise().getEnBrands();
		if (brands == null) {
            throw new SystemError(ErrorUtils.NO_BRAND_FOUND);
        }
		return iteratorCustTasks(custId, new ICallable<CustData<Stock>, Vendor>() {

			@Override
			public CustData<Stock> call(Vendor cust) throws Exception {
				return new CustData<Stock>(cust, custDataService.findProductStockInfo(cust.getMyEnUU(), brands));
			}

		});
	}

	/**
	 * 取销售订单信息
	 * 
	 * <pre>
	 * 从{@code startDate}截止到当前时间
	 * </pre>
	 * 
	 * @param custId
	 *            指定客户企业ID
	 * @param org_item
	 *            指定原厂型号
	 * @param startDate
	 *            指定开始时间
	 */
	@RequestMapping(params = "type=sale_order")
	public List<CustData<Sale>> getSaleItems(Long custId, final String org_item, String startDate) {
		if (startDate != null && !startDate.matches(dateFormat)) {
            throw new SystemError(ErrorUtils.DATE_FORMAT_ERROR);
        }
		final String brands = SystemSession.getUser().getEnterprise().getEnBrands();
		if (brands == null) {
            throw new SystemError(ErrorUtils.NO_BRAND_FOUND);
        }
		// 起始日期为空则取当月第一天
		final String _startDate = startDate == null ? DateUtils.getMinMonthDateS(new Date()) : startDate;
		return iteratorCustTasks(custId, new ICallable<CustData<Sale>, Vendor>() {

			@Override
			public CustData<Sale> call(Vendor cust) throws Exception {
				return new CustData<Sale>(cust, custDataService.findSales(cust.getMyEnUU(), brands, org_item, _startDate));
			}

		});
	}

	/**
	 * 取出入库信息
	 * 
	 * <pre>
	 * 从{@code startDate}截止到当前时间
	 * </pre>
	 * 
	 * @param custId
	 *            指定客户企业ID
	 * @param org_item
	 *            指定原厂型号
	 * @param startDate
	 *            指定开始时间
	 */
	@RequestMapping(params = "type=stock_io")
	public List<CustData<IO>> getIOItems(Long custId, final String org_item, String startDate) {
		if (startDate != null && !startDate.matches(dateFormat)) {
            throw new SystemError(ErrorUtils.DATE_FORMAT_ERROR);
        }
		final String brands = SystemSession.getUser().getEnterprise().getEnBrands();
		if (brands == null) {
            throw new SystemError(ErrorUtils.NO_BRAND_FOUND);
        }
		// 起始日期为空则取当月第一天
		final String _startDate = startDate == null ? DateUtils.getMinMonthDateS(new Date()) : startDate;
		return iteratorCustTasks(custId, new ICallable<CustData<IO>, Vendor>() {

			@Override
			public CustData<IO> call(Vendor cust) throws Exception {
				return new CustData<IO>(cust, custDataService.findIOs(cust.getMyEnUU(), brands, org_item, _startDate));
			}

		});
	}

	/**
	 * 取销售预测信息
	 * 
	 * <pre>
	 * 从{@code startDate}截止到当前时间
	 * </pre>
	 * 
	 * @param custId
	 *            指定客户企业ID
	 * @param org_item
	 *            指定原厂型号
	 * @param startDate
	 *            指定开始时间
	 */
	@RequestMapping(params = "type=sale_forecast")
	public List<CustData<Forecast>> getForecastItems(Long custId, final String org_item, String startDate) {
		if (startDate != null && !startDate.matches(dateFormat)) {
            throw new SystemError(ErrorUtils.DATE_FORMAT_ERROR);
        }
		final String brands = SystemSession.getUser().getEnterprise().getEnBrands();
		if (brands == null) {
            throw new SystemError(ErrorUtils.NO_BRAND_FOUND);
        }
		// 起始日期为空则取当月第一天
		final String _startDate = startDate == null ? DateUtils.getMinMonthDateS(new Date()) : startDate;
		return iteratorCustTasks(custId, new ICallable<CustData<Forecast>, Vendor>() {

			@Override
			public CustData<Forecast> call(Vendor cust) throws Exception {
				return new CustData<Forecast>(cust, custDataService.findForecasts(cust.getMyEnUU(), brands, org_item, _startDate));
			}

		});
	}

	/**
	 * 遍历客户资料，并异步执行取数据操作
	 * 
	 * @param custId
	 * @param callable
	 */
	private <T> List<T> iteratorCustTasks(Long custId, ICallable<T, Vendor> callable) {
		List<Vendor> custs = null;
		if (custId != null) {
			custs = vendorService.findMyCustomerUsingErp(custId);
			// 指定的企业ID错误，或该企业并非您的客户
			if (CollectionUtils.isEmpty(custs)) {
                throw new SystemError(ErrorUtils.EN_IS_NOT_YOUR_CUST);
            }
		} else {
            custs = vendorService.findMyCustomersUsingErp();
        }
		List<T> datas = new ArrayList<T>();
		if (!CollectionUtils.isEmpty(custs)) {
			// 定义一个缓冲的线程池
			ExecutorService threadPool = Executors.newCachedThreadPool();
			CompletionService<T> cs = new ExecutorCompletionService<T>(threadPool);
			for (final Vendor cust : custs) {
				cs.submit(new ICallableAdapter<T, Vendor>(callable, cust));
			}
			threadPool.shutdown();
			int count = 0, len = custs.size();
			while (count < len) {
				// 非阻塞方式
				Future<T> future = cs.poll();
				if (future != null) {
					try {
						datas.add(future.get());
					} catch (InterruptedException e) {
						e.printStackTrace();
					} catch (ExecutionException e) {
						e.printStackTrace();
					}
					count++;
				}
				if (count < len) {
                    try {
                        // 等待50毫秒再进入下一次查找
                        TimeUnit.MILLISECONDS.sleep(50);
                    } catch (InterruptedException e) {
                    }
                }
			}
		}
		return datas;
	}

}
