package com.artfess.base.controller;

import java.io.Serializable;
import java.lang.reflect.Method;
import java.util.ArrayList;

import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.annotation.Resource;

import com.artfess.base.annotation.ApiGroup;
import com.artfess.base.cache.CacheManager;
import com.artfess.base.cache.ICache;
import com.artfess.base.conf.JwtConfig;
import com.artfess.base.conf.SaaSConfig;
import com.artfess.base.constants.ApiGroupConsts;
import com.artfess.base.constants.CacheKeyConst;
import com.artfess.base.constants.TenantConstant;
import com.artfess.base.model.CommonResult;
import com.artfess.base.query.PageList;
import com.artfess.base.util.StringUtil;
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.RestController;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;


import io.jsonwebtoken.lang.Assert;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;

@RestController
@RequestMapping("/base/online/v1/")
@Api(tags="在线用户")
@ApiGroup(group= {ApiGroupConsts.GROUP_SYSTEM,ApiGroupConsts.GROUP_APPLICATION,ApiGroupConsts.GROUP_UC})
public class OnlineUserController {
	@Resource
	CacheManager cacheManager;
	@Resource
	JwtConfig jwtConfig;
	@Resource
	SaaSConfig saaSConfig;
	// 是否已经初始化
	Boolean initialized = false;
	// 缓存操作对象
	ICache cache = null;
	// 原生缓存操作对象
	Object nativeCache = null;

	Pattern regex = Pattern.compile(String.format("^%s:(\\w+)_(.*?)_(\\w+)_(.*?)_.*?$",CacheKeyConst.EIP_UC_USER_TOKEN));

	private void initialNativeCache() {
		if(initialized) {
			return;
		}
		/*if(!jwtConfig.isSingle() || !jwtConfig.isStricty()) {
			return;
		}*/
		Collection<ICache> cacheGroup = cacheManager.getCache(CacheKeyConst.EIP_UC_USER_TOKEN);
		if(cacheGroup==null || cacheGroup.size() < 1) {
			return;
		}
		initialized = true;
		// 非租户模式，正则表达式需要修正
		if(!saaSConfig.isEnable()) {
			regex = Pattern.compile(String.format("^%s:(\\w+)_(.*?)_(\\w+)$", CacheKeyConst.EIP_UC_USER_TOKEN));
		}
		cache = cacheGroup.iterator().next();
		nativeCache = cache.getNativeCache();
		String canonicalName = nativeCache.getClass().getCanonicalName();
		if(StringUtil.isEmpty(canonicalName) || !"org.springframework.data.redis.core.RedisTemplate".equalsIgnoreCase(canonicalName)) {
			nativeCache = null;
			return;
		}
	}

	@RequestMapping(value = "/users", method = RequestMethod.POST, produces = {"application/json; charset=utf-8" })
	@ApiOperation(value = "获取在线用户", httpMethod = "POST", notes = "获取在线用户")
	public PageList<OnlineUser> online() throws Exception {
		initialNativeCache();
		Assert.notNull(nativeCache, "无法获取在线用户");
		Object invoke = invoke(nativeCache, String.format("%s:*", CacheKeyConst.EIP_UC_USER_TOKEN));
		IPage<OnlineUser> result = new Page<>();
		if(invoke instanceof HashSet) {
			Set<?> sets = (HashSet<?>)invoke;
			int size = sets.size();
			result.setTotal(size);
			List<OnlineUser> list = new ArrayList<>();
			result.setRecords(list);
			sets.forEach(item -> {
				Matcher matcher = regex.matcher(item.toString());
				if(matcher.matches()) {
					String loginType = matcher.group(1);
					String tenantId = matcher.group(2);
					String account = matcher.group(3);
					String ip = matcher.group(4);
					list.add(new OnlineUser(account, loginType, tenantId,ip));
				}
			});
		}
		return new PageList<>(result);
	}

	@RequestMapping(value = "/kickoff", method = RequestMethod.POST, produces = {"application/json; charset=utf-8" })
	@ApiOperation(value = "踢指定用户下线", httpMethod = "POST", notes = "踢指定用户下线")
	public CommonResult<String> kickoff(@ApiParam(name="user",value="账号") @RequestBody(required=true) OnlineUser user) throws Exception {
		initialNativeCache();
		String account = user.getAccount();
		Assert.isTrue(StringUtil.isNotEmpty(account), "用户账号不能为空");
		String loginType = StringUtil.isNotEmpty(user.getLoginType()) ? user.getLoginType() : "pc";
		String tenantId = StringUtil.isNotEmpty(user.getTenantId()) ? user.getTenantId() : TenantConstant.PLATFORM_TENANT_ID;
		String ip = user.getIp();
		cache.evict(String.format("%s_%s_%s_%s_%s",loginType,tenantId,account,ip,tenantId));
		return new CommonResult<String>();
	}
	
	@RequestMapping(value = "/kickall", method = RequestMethod.POST, produces = {"application/json; charset=utf-8" })
	@ApiOperation(value = "踢所有用户下线", httpMethod = "POST", notes = "踢所有用户下线")
	public CommonResult<String> kickall() throws Exception {
		cacheManager.clearCascadeByKey(CacheKeyConst.EIP_UC_USER_TOKEN);
		return new CommonResult<String>();
	}

	private Object invoke(Object obj, String param) throws Exception {
		Class<?> clazz = obj.getClass();
		Method method = clazz.getMethod("keys", Object.class);
		return method.invoke(obj, param);
	}

	@ApiModel(description="用户表")
	public static class OnlineUser implements Serializable{
		private static final long serialVersionUID = 1L;
		@ApiModelProperty("账号")
		private String account;
		@ApiModelProperty(value="设备类型", allowableValues = "pc,mobile")
		private String loginType;
		@ApiModelProperty("租户ID")
		private String tenantId;
		@ApiModelProperty("登录用户IP")
		private String ip;

		public OnlineUser() {}

		public OnlineUser(String account, String loginType, String tenantId,String ip) {
			this.account = account;
			this.loginType = loginType;
			this.tenantId = tenantId;
			this.ip = ip;
		}

		public String getAccount() {
			return account;
		}
		public void setAccount(String account) {
			this.account = account;
		}
		public String getLoginType() {
			return loginType;
		}
		public void setLoginType(String loginType) {
			this.loginType = loginType;
		}
		public String getTenantId() {
			return tenantId;
		}
		public void setTenantId(String tenantId) {
			this.tenantId = tenantId;
		}
		public String getIp() {
			return ip;
		}
		public void setIp(String ip) {
			this.ip = ip;
		}
	}
}
