package org.springblade.face.controller;


import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import javax.servlet.http.HttpServletRequest;

import org.springblade.core.mp.support.Condition;
import org.springblade.core.mp.support.Query;
import org.springblade.core.secure.BladeUser;
import org.springblade.core.secure.utils.AuthUtil;
import org.springblade.core.tool.api.R;
import org.springblade.face.data.LoginTypeData;
import org.springblade.face.entity.LoginRecord;
import org.springblade.face.query.PageQuery;
import org.springblade.face.query.UserLoginRecordQuery;
import org.springblade.face.service.ILoginRecordService;
import org.springblade.face.util.ipaddress.CityUtil;
import org.springblade.face.vo.LoginRecordExportVO;
import org.springblade.face.vo.LoginRecordTotalExportVO;
import org.springblade.face.vo.UserLoginRecordExportVO;
import org.springblade.face.vo.UserLoginRecordVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;

import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;

/**
 * <p>
 * 登录记录表 前端控制器
 * </p>
 *
 * @author zbc
 * @since 2021-07-05
 */
@RestController
@RequestMapping("loginRecord")
@Slf4j
@Api(value = "登录记录", tags = "登录记录接口")
public class LoginRecordController {

	@Autowired
	private ILoginRecordService loginRecordService;


	@PostMapping("/export")
	@ApiOperation(value = "登陆记录详单/总单导出")
	public R export(String month) {
		if(StrUtil.isBlank(month)){
			return R.fail("参数异常");
		}
		String tempFileName = "登陆记录详单-总单" + month + ".xlsx";
		String filePath = picDir + tempFileName;
		ExcelWriter excelWriter = EasyExcel.write(filePath).build();
		//详单内容
		List<LoginRecordExportVO> list = loginRecordService.getLoginRecordDetailByMonth(month);
		WriteSheet writeSheet = EasyExcel.writerSheet(0, "登录记录详单").head(LoginRecordExportVO.class).build();
		excelWriter.write(list,writeSheet);

		//总单内容
		List<LoginRecordTotalExportVO> totalList = loginRecordService.getLoginRecordTotalByMonth(month);
		WriteSheet writeSheet1 = EasyExcel.writerSheet(1,"登录记录总单").head(LoginRecordTotalExportVO.class).build();
		excelWriter.write(totalList,writeSheet1);
		excelWriter.finish();
		return R.success("uploads/" + tempFileName);
	}


	@GetMapping("/detailList")
	@ApiOperation(value = "IP预警列表", notes = "传入query")
	public R<IPage<UserLoginRecordVO>> detailList(UserLoginRecordQuery recordQuery, Query query) {
		IPage<UserLoginRecordVO> page = Condition.getPage(query);
		IPage<UserLoginRecordVO> pages = loginRecordService.getLoginRecordPage(page, recordQuery);
		List<UserLoginRecordVO> records = pages.getRecords();

		Date date = new Date();
		DateFormat format = new SimpleDateFormat("yyyy-MM-dd");
		Calendar c = new GregorianCalendar();
		c.setTime(date);
		c.set(Calendar.DAY_OF_MONTH,1);
		String beginTime = format.format(c.getTime());

		c.set(Calendar.DAY_OF_MONTH,c.getActualMaximum(Calendar.DAY_OF_MONTH));
		String endTime = format.format(c.getTime());

		for (UserLoginRecordVO record : records) {
			LoginRecord loginRecord = loginRecordService.getOne(new LambdaQueryWrapper<LoginRecord>()
				.eq(LoginRecord::getUserId, record.getUserId())
				.orderByDesc(LoginRecord::getLoginTime)
				.last("limit 1")
			);
			if (loginRecord != null) {
				record.setLoginIp(loginRecord.getLoginIp());
				record.setLoginTime(loginRecord.getLoginTime());
			}

			int count = (int)loginRecordService.count(new LambdaQueryWrapper<LoginRecord>()
				.eq(LoginRecord::getUserId, record.getUserId())
				.ge(LoginRecord::getLoginTime, beginTime)
				.le(LoginRecord::getLoginTime, endTime)
			);
			record.setLoginNum(count);
		}

		return R.data(pages);
	}


	@GetMapping("/statusNumber")
	@ApiOperation(value = "账号状态数", notes = "传入query")
	public R statusNumber(UserLoginRecordQuery recordQuery, Query query) {
		List<UserLoginRecordVO> records = loginRecordService.getLoginRecordNum(recordQuery);
		long greenNum = records.stream().filter(vo -> "0".equals(vo.getLoginStatus())).count();
		long orangeNum = records.stream().filter(vo -> "1".equals(vo.getLoginStatus())).count();
		long redNum = records.stream().filter(vo -> "2".equals(vo.getLoginStatus())).count();
		Map<String, Object> map = new HashMap<>();
		map.put("normal", greenNum);
		map.put("Warning", orangeNum);
		map.put("Danger", redNum);
		return R.data(map);
	}


	@GetMapping("/page")
	@ApiOperation(value = "分页", notes = "传入query")
	public R<IPage<LoginRecord>> page(PageQuery pageQuery, Query query) {
		IPage<LoginRecord> page = Condition.getPage(query);
		IPage<LoginRecord> pages = loginRecordService.page(page, new LambdaQueryWrapper<LoginRecord>()
			.eq(LoginRecord::getUserId,pageQuery.getUserId())
			.orderByDesc(LoginRecord::getLoginTime));
		return R.data(pages);
	}


	@PostMapping("/trigger")
	@ApiOperation(value = "登录记录触发", notes = "登录记录触发")
	public R uploadFile(@RequestBody LoginTypeData LoginTypeData, HttpServletRequest request) {
		if(LoginTypeData == null || LoginTypeData.getLoginType() == null){
			return R.fail("登录类型不能为空");
		}
		try {
			BladeUser user = AuthUtil.getUser();
			String ip = getIp(request);
			String address = CityUtil.getAddress(ip);
			if(StrUtil.isNotBlank(ip) && "127.0.0.1".equals(ip)){
				return R.success("记录成功");
			}
			JSONObject json = JSON.parseObject(address);
			String country = StrUtil.isNotBlank(json.getString("country_name"))?json.getString("country_name"):"";
			String region = StrUtil.isNotBlank(json.getString("region_name"))?json.getString("region_name"):"";
			String city = StrUtil.isNotBlank(json.getString("city_name"))?json.getString("city_name"):"";
			String addressStr = country+"-"+region+"-"+city;
			if (user != null && StrUtil.isNotBlank(ip) && StrUtil.isNotBlank(address)) {
				loginRecordService.save(new LoginRecord()
					.setLoginType(LoginTypeData.getLoginType())
					.setLoginUser(user.getUserName())
					.setUserId(user.getUserId())
					.setLoginIp(ip)
					.setLoginAddress(addressStr)
					.setLoginTime(new Date())
					.setCreateTime(new Date())
				);
			}
		} catch (Exception e) {
			log.error(e.getMessage(), e);
			return R.fail("记录失败");
		}
		return R.success("记录成功");
	}


	/**
	 * 根据ip获取地址
	 *
	 * @param ip
	 * @return
	 */
	private String getAddress(String ip) {
		String url = "http://ip.ws.126.net/ipquery?ip=" + ip;
		String str = HttpUtil.get(url);
		if (StrUtil.isNotBlank(str)) {
			String substring = str.substring(str.indexOf("{"), str.indexOf("}") + 1);
			JSONObject parse = JSONObject.parseObject(substring);
			String province = parse.getString("province");
			String city = parse.getString("city");
			return province + city;
		}
		return null;
	}

	/**
	 * 获取ip地址
	 *
	 * @param request
	 * @return
	 */
	private String getIp(HttpServletRequest request) {
		String ip = request.getHeader("X-Forwarded-For");
		if (StrUtil.isNotEmpty(ip) && !"unKnown".equalsIgnoreCase(ip)) {
			int index = ip.indexOf(",");
			if (index != -1) {
				return ip.substring(0, index);
			} else {
				return ip;
			}
		}
		ip = request.getHeader("X-Real-IP");
		if (StrUtil.isNotEmpty(ip) && !"unKnown".equalsIgnoreCase(ip)) {
			return ip;
		}
		ip = request.getHeader("WL-Proxy-Client-IP");
		if (StrUtil.isNotEmpty(ip) && !"unknown".equalsIgnoreCase(ip)) {
			return ip;
		}
		return request.getRemoteAddr();
	}


	@Value("${blade.file.uploadPath}")
	private String picDir;


	@GetMapping("/exportRecord")
	@ApiOperation(value = "登录记录导出", notes = "传入recordQuery")
	public R exportRecord(UserLoginRecordQuery recordQuery, Query query) {
		IPage<UserLoginRecordVO> page = Condition.getPage(query);
		IPage<UserLoginRecordVO> pages = loginRecordService.getLoginRecordPage(page, recordQuery);
		List<UserLoginRecordVO> records = pages.getRecords();

		Date date = new Date();
		DateFormat format = new SimpleDateFormat("yyyy-MM-dd");
		Calendar c = new GregorianCalendar();
		c.setTime(date);
		c.set(Calendar.DAY_OF_MONTH,1);
		String beginTime = format.format(c.getTime());

		c.set(Calendar.DAY_OF_MONTH,c.getActualMaximum(Calendar.DAY_OF_MONTH));
		String endTime = format.format(c.getTime());

		for (UserLoginRecordVO record : records) {
			if("0".equals(record.getLoginStatus())){
				record.setLoginStatus("正常");
			}else if("1".equals(record.getLoginStatus())){
				record.setLoginStatus("预警");
			}else if("2".equals(record.getLoginStatus())){
				record.setLoginStatus("警告");
			}

			LoginRecord loginRecord = loginRecordService.getOne(new LambdaQueryWrapper<LoginRecord>()
				.eq(LoginRecord::getUserId, record.getUserId())
				.orderByDesc(LoginRecord::getLoginTime)
				.last("limit 1")
			);
			if (loginRecord != null) {
				record.setLoginIp(loginRecord.getLoginIp());
				record.setLoginTime(loginRecord.getLoginTime());
			}

			int count = (int)loginRecordService.count(new LambdaQueryWrapper<LoginRecord>()
				.eq(LoginRecord::getUserId, record.getUserId())
				.ge(LoginRecord::getLoginTime, beginTime)
				.le(LoginRecord::getLoginTime, endTime)
			);
			record.setLoginNum(count);
		}

		String tempFileName = UUID.randomUUID().toString() + RandomUtil.randomString(4) + ".xls";
		try {
			String filePath = picDir + tempFileName;
			//String filePath = "D:/boyuan/work2/excel/" + tempFileName;
			EasyExcel.write(filePath, UserLoginRecordExportVO.class).sheet().doWrite(records);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return R.success("uploads/" + tempFileName);
	}


}

