package com.yizhi.application.sign.controller;

import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import com.yizhi.core.application.context.RequestContext;
import com.yizhi.core.application.context.TaskContext;
import com.yizhi.core.application.file.task.AbstractDefaultTask;
import com.yizhi.sign.application.feign.ReportSignClient;
import com.yizhi.sign.application.feign.SignManageClient;
import com.yizhi.sign.application.feign.SignRecordApiClient;
import com.yizhi.sign.application.vo.SignRecordImportVO;
import com.yizhi.sign.application.vo.domain.TrSign;
import com.yizhi.sign.application.vo.domain.TrSignRecord;
import com.yizhi.sign.application.vo.domain.TrSignTime;
import com.yizhi.system.application.model.AccountNameForIdsModel;
import com.yizhi.system.application.system.remote.AccountClient;
import com.yizhi.system.application.vo.AccountVO;
import com.yizhi.training.application.feign.TrainingProjectClient;
import com.yizhi.training.application.vo.domain.TpAuthorizationRangeVo;
import org.apache.commons.collections.CollectionUtils;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class SignRecordImport extends AbstractDefaultTask<String, Map<String, Object>> {

    private static final Logger LOGGER = LoggerFactory.getLogger(SignRecordImport.class);

    @Autowired
    private AccountClient accountClient;
    
    @Autowired
    private SignRecordApiClient signRecordApiClient;
    
    @Autowired
    private SignManageClient signManageClient;
    
    @Autowired
    private TrainingProjectClient trainingProjectClient;

    @Autowired
    private ReportSignClient reportSignClient;
    
    @Override
    protected String execute(Map<String, Object> map) {
        Long taskId = (Long) map.get("taskId");
        String serialNo = (String) map.get("serialNo");
        String taskName = (String) map.get("taskName");
        String ossUrl = (String) map.get("url");
        URL url = null;
        HttpURLConnection conn = null;
        InputStream inputStream = null;
        Workbook book = null;

        RequestContext res = (RequestContext) map.get("res");
        Long signId = (Long) map.get("signId");
        Long accountId = res.getAccountId();
        Long companyId = res.getCompanyId();
        Long siteId = res.getSiteId();
        Date submitTime = new Date();
        TaskContext taskContext = new TaskContext(taskId, serialNo, taskName, accountId, submitTime, siteId, companyId);
        working(taskContext);
        List<SignRecordImportVO> rowVOS = new ArrayList<>();
        SignRecordImportVO rowVO = null;
        List<String> names = new ArrayList<>();
        List<Integer> errorList = new ArrayList<>();
        List<String> errors = new ArrayList<String>();
        TrSignTime trSignTime = reportSignClient.getSignTime(signId);
        try {
            //解析url
            String fileName = ossUrl.substring(ossUrl.lastIndexOf("/") + 1);
            String ossUrlPrefix = ossUrl.substring(0, ossUrl.lastIndexOf("/") + 1);
            ossUrl = ossUrlPrefix + URLEncoder.encode(fileName, "utf-8");

            url = new URL(ossUrl);
            conn = (HttpURLConnection) url.openConnection();
            //防止屏蔽程序抓取而返回403错误
            conn.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)");
            inputStream = conn.getInputStream();
            book = WorkbookFactory.create(inputStream);
        } catch (MalformedURLException e) {
            LOGGER.error("创建ossurl 连接错误", e);
            fail(taskContext, "创建ossurl 连接错误");
        } catch (IOException e) {
            LOGGER.error("创建ossurl 连接错误", e);
            fail(taskContext, "创建ossurl 连接错误");
        } catch (InvalidFormatException e) {
            LOGGER.error("创建Workbook 对象错误", e);
            fail(taskContext, "创建ossurl 连接错误");
        }

        try {
            if (null == book) {
                fail(taskContext, "创建Workbook 对象失败");
            }
            Sheet sheet = book.getSheetAt(0);
            Row row;
            Cell cell0;
            Cell cell1;
            Cell cell2;
            int lastRowNum = sheet.getLastRowNum();
            //获取每行值
            if (lastRowNum > 0) {
                for (int i = 1; i < lastRowNum; i++) {
                    String name = null;
                    Date signTime = null;
                    String isSign = null;
                    String signTimeString = null;
                    row = sheet.getRow(i + 1);
                    if (null != row) {
                        cell0 = row.getCell(2);
                        cell1 = row.getCell(5);
                        cell2 = row.getCell(4);
                        if (null != cell0) {
                            if (cell0.getCellTypeEnum().equals(CellType.STRING)) {
                                name = cell0.getStringCellValue();
                            } else if (cell0.getCellTypeEnum().equals(CellType.NUMERIC)) {
                                cell0.setCellType(CellType.STRING);
                                name = cell0.getStringCellValue();
                            }
                        }
                        if (null != cell1) {
                            if (cell1.getCellTypeEnum().equals(CellType.STRING)) {
                            	signTimeString = cell1.getStringCellValue();
                            } else if (cell1.getCellTypeEnum().equals(CellType.NUMERIC)) {
                            	cell1.setCellType(CellType.STRING);
                            	signTimeString = cell1.getStringCellValue();
                            }
                        	LOGGER.info("签到时间: "+signTimeString);
                            if (signTimeString!=null&&signTimeString!="") {
                            	signTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(signTimeString.replaceAll("/", "-"));
							}       
                        }
                        if (null != cell2) {
                            if (cell2.getCellTypeEnum().equals(CellType.STRING)) {
                                isSign = cell2.getStringCellValue();
                            } else if (cell2.getCellTypeEnum().equals(CellType.NUMERIC)) {
                                cell2.setCellType(CellType.STRING);
                                isSign = cell2.getStringCellValue();
                            }
                        }
                        if (null != name && null != signTime&&null!=isSign) {
                        	if (signTime.before(trSignTime.getStartTime())) {
                                errorList.add(i + 2);
								errors.add("签到时间有误");
								LOGGER.info("签到时间有误");
							}else {
	                            rowVO = new SignRecordImportVO();
	                            rowVO.setName(name.trim());
	                            rowVO.setSignTime(signTime);
	                            rowVO.setIsSign(isSign);
	                            rowVO.setRowNumber(i + 2);
	                            rowVOS.add(rowVO);
	                            names.add(name.trim());
							}
                        } else {
                            errorList.add(i + 2);
                            errors.add("导入格式有误");
                        }
                    }
                }
            } else {
                success(taskContext, "执行成功,未检索到数据", "");
            }

            //通过用户名找出对应的用户id
            Map<String, Map<String, Object>> nameMap = new HashMap<>();
            if (CollectionUtils.isNotEmpty(names)) {
                AccountNameForIdsModel model = new AccountNameForIdsModel(names, res);
                nameMap = accountClient.getAccountByNames(model, companyId, siteId, "statistics_sign");
            }
            List<Long> accountIds = new ArrayList<Long>();
            TrSign sign = signManageClient.getSignByTime(signId);
            List<TpAuthorizationRangeVo> visibleRanges = trainingProjectClient.VisibleRange(sign.getTrainingProjectId());
            if (CollectionUtils.isNotEmpty(visibleRanges)) {
                for(TpAuthorizationRangeVo visibleRange:visibleRanges) {
                	if (2==visibleRange.getType()) {
    					accountIds.add(visibleRange.getRelationId());
    				}else if (1==visibleRange.getType()) {
    					List<AccountVO> list = accountClient.findByOrgId(visibleRange.getRelationId(), companyId);
    					for(AccountVO accountVO:list) {
    						accountIds.add(accountVO.getId());
    					}
    				}
                	LOGGER.info("可见范围："+accountIds.toString());
                }
			}else {
				Set<Entry<String, Map<String, Object>>> entrySet = nameMap.entrySet();
				for(Entry<String, Map<String, Object>> entry:entrySet) {
					accountIds.add(Long.valueOf(entry.getValue().get("accountId").toString()));
				}
			}
            List<SignRecordImportVO> list = new ArrayList<>();
            if (null != nameMap && nameMap.size() > 0) {
                for (SignRecordImportVO sheetRowVO : rowVOS) {
                    if (nameMap.containsKey(sheetRowVO.getName())) {
                        Map<String, Object> accountMap = new HashMap<>(3);
                        accountMap = nameMap.get(sheetRowVO.getName());
                        Long id = Long.valueOf(accountMap.get("accountId").toString());
                        if (accountIds.contains(id)) {
                        	LOGGER.info("线下签到导入accountId:"+id);
                            sheetRowVO.setAccountId(id);
                            sheetRowVO.setOrgId(Long.valueOf(accountMap.get("orgId").toString()));
                            sheetRowVO.setOrgName((String) accountMap.get("orgName"));
                            list.add(sheetRowVO);
						}else {
	                        errorList.add(sheetRowVO.getRowNumber());
	                        errors.add("该用户未在可见范围内");
	                        LOGGER.info("该用户未在可见范围内");
						}
                    } else {
                        errorList.add(sheetRowVO.getRowNumber());
                        errors.add("该用户未在可见范围内");
                    }
                }
            }
            List<TrSignRecord> insertList = new ArrayList<>();
            TrSignRecord trSignRecord = null;
            //建立对象,批量插入对应用户Id的线下签到记录
            if (CollectionUtils.isNotEmpty(list)) {
                for (SignRecordImportVO rowVO1 : list) {
                	trSignRecord = new TrSignRecord();
                	trSignRecord.setSignId(signId);
                	trSignRecord.setSignTime(rowVO1.getSignTime());
                	trSignRecord.setAccountId(rowVO1.getAccountId());
                	trSignRecord.setType(0);
                	if (rowVO1.getIsSign().equals("已签到")) {
                        insertList.add(trSignRecord);
					}
                }
            }
            boolean isOk = false;
            if (CollectionUtils.isNotEmpty(insertList)) {
                if (insertList.size() > 2000) {
                    int n = insertList.size() / 2000;
                    for (int i = 0; i < n; i++) {
                        isOk = signRecordApiClient.insertSignRecordList(insertList.subList(2000 * i, 2000 * i + 2000));
                    }
                    if ((insertList.size() % 2000) > 0) {
                        isOk = signRecordApiClient.insertSignRecordList(insertList.subList(2000 * n, insertList.size()));
                    }
                } else {
                    isOk = signRecordApiClient.insertSignRecordList(insertList);
                }

            }
            if (isOk) {
                Integer n = insertList.size();
                if (CollectionUtils.isNotEmpty(errorList) && (CollectionUtils.isNotEmpty(errors))) {
                    success(taskContext, "成功导入" + n + "条,第" + errorList.toString() +"行"+ errors.toString(), "");
                } else if (CollectionUtils.isNotEmpty(errorList)) {
                    success(taskContext, "成功导入" + n + "条,第" + errorList.toString() + "行导入格式有误", "");
                } else if (CollectionUtils.isNotEmpty(errors)) {
                    success(taskContext, "成功导入" + n + "条,第" +"行"+ errors.toString(), "");
				}else if (CollectionUtils.isEmpty(errorList)&& CollectionUtils.isEmpty(errors)) {
                    success(taskContext, "成功导入" + n + "条,失败0条", "");
                }
            } else {
                if (CollectionUtils.isNotEmpty(errorList) && (CollectionUtils.isNotEmpty(errors))) {
                    fail(taskContext, "成功导入" + 0 + "条,第" + errorList.toString()+"行"+ errors.toString());
                } else if (CollectionUtils.isNotEmpty(errorList)) {
                    fail(taskContext, "成功导入" + 0 + "条,第" + errorList.toString() + "行导入格式有误");
                }else if (CollectionUtils.isNotEmpty(errors)) {
                	fail(taskContext, "成功导入" + 0 + "条,第"+ errors.toString());
				} else if (CollectionUtils.isEmpty(errorList) && CollectionUtils.isEmpty(errors)) {
                    fail(taskContext, "成功导入0条,未检索到相关数据 ");
                }
            }
        } catch (Exception e1) {
            LOGGER.error("线下签到导入过程出现错误:", e1);
            fail(taskContext, "线下签到导入过程出现错误");
        }
        return "ok";
    }
}
