package com.group.job;

import com.data.bean.*;
import com.data.cache.*;
import com.data.util.ErrorCode;
import com.group.service.GroupPublisherService;
import com.taurus.core.entity.ITArray;
import com.taurus.core.entity.ITObject;
import com.taurus.core.entity.TArray;
import com.taurus.core.entity.TObject;
import com.taurus.core.plugin.database.DataBase;
import com.taurus.core.plugin.redis.Redis;
import com.taurus.core.util.Logger;
import com.taurus.core.util.MD5;
import com.taurus.core.util.StringUtil;
import com.taurus.core.util.Utils;
import com.taurus.web.WebException;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobKey;
import org.slf4j.helpers.Util;
import redis.clients.jedis.Jedis;

import java.io.*;
import java.net.URL;
import java.util.*;
import java.util.concurrent.CompletableFuture;

import static com.group.service.GroupRoomService._getSvr;

public class UpdateRobotRoomJob implements Job{

	private Logger logger = Logger.getLogger(UpdateRobotRoomJob.class);

	public static final String CHANNEL_NAME = "mgr_group";

	private static final String CMD_DEL_ROOM="del_room";
	private static final String CMD_UPDATE_ROOM="update_room";

	public UpdateRobotRoomJob() {
		
    }


	/**解散时间*/
	private static final String[] DISMISS_TIME = {"30","60","90","180"};
	/**踢出时间*/
	private static final String[] KICK_TIME = {"30","60","120","180"};



	/**
	 * 更新redis回合
	 */
	private void updateRound(String roomKey, int groupId,String roomid, int round) {
		Redis.use().hset(roomKey, "round", Integer.toString(round));
		roomUpdateEvent(roomKey, groupId, roomid);
	}

	/**
	 * list to TArray
	 * @param list
	 * @return
	 */
	public static final ITArray toTArray(List<Integer> list) {
		ITArray result = new TArray();
		for (Integer card : list) {
			result.addInt(card);
		}
		return result;
	}


	/**
	 * 更新房间redis数据
	 */
	public void updateRedisMap(int groupId, String roomId, String roomKey, Map<String, String> redis_room_map, int maxPlayers) {
		Map<Integer, Integer> playerMapBySeat = new HashMap<Integer, Integer>();
		for(int i = 1; i <= maxPlayers; i++)
		{
			playerMapBySeat.put(i, getRobot(maxPlayers));
		}

		Iterator<Map.Entry<Integer, Integer>> it = playerMapBySeat.entrySet().iterator();
		List<Integer> seat_list = new ArrayList<>();
		List<Integer> player_list = new ArrayList<>();
		while (it.hasNext()) {
			Map.Entry<Integer, Integer> entry = (Map.Entry<Integer, Integer>) it.next();
			seat_list.add(entry.getKey());
			player_list.add(entry.getValue());
		}
		redis_room_map.put("players", toTArray(player_list).toJson());
		redis_room_map.put("seats", toTArray(seat_list).toJson());
		Redis.use().hmset(roomKey, redis_room_map);
		updateRound(roomKey, groupId, roomId, 0);
	}

	/**
	 * 玩家加入房间刷新总服圈子缓存
	 */
	public void roomUpdateEvent(String roomKey, int groupId,String roomid) {
		Redis.use("group1_db0").hincrBy(roomKey, "cache_ver", 1);
		updateRoomEvt(groupId, roomid);
	}


	/**
	 * 更新房间事件
	 * @param groupId
	 * @param roomid
	 */
	public static void updateRoomEvt(int groupId,String roomid) {
		if(groupId == 0)return;
		ITObject data = TObject.newInstance();
		data.putInt("gid", groupId);
		data.putUtfString("roomid", roomid);
		data.putUtfString("cmd", CMD_UPDATE_ROOM);
		Redis.use("group1_db11").publish(CHANNEL_NAME, data.toJson());
	}

	@Override
	public void execute(JobExecutionContext context) {
		
		JobKey jobKey = context.getJobDetail().getKey();
		if(jobKey.getName().equals("update_robot_room") ) {
			updateRobotRoom();
		}else if(jobKey.getName().equals("create_robot_room") ) {
			createRobotRoom();
		}
	}

	public void updateRobotRoom(){

		Jedis js2 = Redis.use("group1_db2").getJedis();
		Jedis js0 = Redis.use("group1_db0").getJedis();
		Jedis js11 = Redis.use("group1_db11").getJedis();
		String wokelock = "wokelock";
		try{
			int groupId = 426149;
			String gp_key = GroupCache.genPidsKey(groupId);
			Set<String> pids = Redis.use("group1_db11").zrangeByScore(gp_key, 9, 66);

			if (pids.size() == 0) {
				return;
			}
			GroupBean gb = GroupCache.getGroup(groupId);
			if (gb == null)
			{
				return;
			}
			for (String str : pids) {
				int pid = Integer.parseInt(str);
				GroupPlayBean gpb = GroupCache.getPlay(groupId, pid);


				//获取所有房间

				//Set<String> rooms = js11.zrevrangeByScore("g{426149}:rooms", min_value, max_value);
				String  allrobotkeys = "{robot426149}";
				int min_value = pid * 10000;
				int max_value = pid * 10000 + 9999;
				String grooms_key = GroupCache.genRoomsKey(groupId);
				Set<String> rooms  = js11.zrevrangeByScore(grooms_key, max_value, min_value);
				long sttime = System.currentTimeMillis() / 1000;
				for (String room : rooms) {
					List<String> room_list = js0.hmget(room, "robot", "status", "create_time", "id", "players","game");
					String robot = room_list.get(0);
					if (robot == null) {
						continue;
					}
					ITArray players = TArray.newFromJsonData(room_list.get(4));
					if (players.size() == 2) {
						//同步状态
						//判断players是否有在机器人中

						continue;
					}

					String roomtime = room_list.get(2);
					if (roomtime == null) {
						continue;
					}
					String gameid = room_list.get(5);
					if (gameid == null) {
						continue;
					}

					String roomId = room_list.get(3);
					int time = Integer.parseInt(roomtime);
					if (time+20 < sttime) {
						if(players.size()>0){
							//判断是否存在
							String s = js2.get(wokelock+players.get(0));
							if(StringUtil.isNotEmpty(s)){
								js2.set(wokelock+players.get(0),1+"");
								js2.expire(wokelock+players.get(0),20);
							}
						}

						//解散房间
						GroupPublisherService.delRoomEvt(groupId, roomId);
						js11.zrem(grooms_key, room);
						Redis.use().hset(room, "status", 3 + "");
						Redis.use().hincrBy(room, "cache_ver", 1);
						Redis.use().expire(room, 20);
					//	logger.error("del 空 robot room:" + roomId + " player:"+room_list.get(4) + " fake_json:");
						continue;
					}

				}
			}

		}catch (Exception e){
			e.printStackTrace();
		}finally {
			js0.close();
			js2.close();
			js11.close();
		}
	}

	public void createRobotRoom() {
		//1、获取对应的机器人id
		Jedis js2 = Redis.use("group1_db2").getJedis();
		Jedis js11 = Redis.use("group1_db11").getJedis();
		String wokelock = "wokelock";
		try{
			int robotid = 0;
			String  allrobotkeys = "{robot426149}";
			int groupid = 426149;
			//获取玩法列表
			Set<String> pids = js11.keys("g{426149}:play:*");
			List<Integer> okpids = new ArrayList<>();
			for (String pid : pids) {
				String gameId = js11.hget(pid,"gameId");
				if(Integer.parseInt(gameId) == 10){
					String rpid = js11.hget(pid,"id");
					okpids.add(Integer.parseInt(rpid));

				}
				if(Integer.parseInt(gameId) == 22){
					String rpid = js11.hget(pid,"id");
					okpids.add(Integer.parseInt(rpid));
				}
				/*if(Integer.parseInt(gameId) == 66){
					//if(Integer.parseInt(pid)==52||Integer.parseInt(pid)==26){
						String rpid = js11.hget(pid,"id");
						okpids.add(Integer.parseInt(rpid));
					//}

				}*/
			}
			//随机生产
			int pidindex = 0;
			int pidindex2 = 0;
			int pidindex3 = 0;
			int pidindex4 = 0;
			int pidindex5 = 0;
			pidindex = new Random().nextInt(okpids.size()-1);
			pidindex2 = new Random().nextInt(okpids.size()-1);
			pidindex3 = new Random().nextInt(okpids.size()-1);
			pidindex4 = new Random().nextInt(okpids.size()-1);
			pidindex5 = new Random().nextInt(okpids.size()-1);


			List<Integer> plist = new ArrayList<>();
			plist.add(okpids.get(pidindex));
			plist.add(okpids.get(pidindex2));
			plist.add(okpids.get(pidindex3));
			plist.add(okpids.get(pidindex4));
			plist.add(okpids.get(pidindex5));

			for(Integer pid : plist) {
				String gameIds = js11.hget("g{426149}:play:"+pid,"gameId");
				Map<String,String> jsRobot= js2.hgetAll(allrobotkeys+gameIds);

				for (String key : jsRobot.keySet()) {

					int tr = new Random().nextInt(60);
					String tmp = js2.get(wokelock+key);
					if(StringUtil.isEmpty(tmp)){
						if(tr<20) {
								//可以工作
							robotid = Integer.parseInt(key);

						}
					}

				}
				if (robotid > 0){
					//查询robotid是否在房间

					Set<String> rooms = null;
					int min_value = 100000;
					int max_value = 999999;
					String grooms_key = GroupCache.genRoomsKey(groupid);
					rooms = js11.zrevrangeByScore(grooms_key, max_value, min_value);
					int qfroomnum = 0;
					boolean flag = true;
					for (String room : rooms) {
						List<String> room_list = Redis.use("group1_db0").hmget(room, "robot", "players");
						String robot = room_list.get(0);
						if (robot == null) {
							continue;
						}
						String playerstr = room_list.get(1);
						if (playerstr.contains(robotid+"")) {
							flag = false;
							break;
						}

					}
					if(flag){
						js2.set(wokelock+robotid,1+"");
						js2.expire(wokelock+robotid,900);
						createGroupRoom(groupid,pid,robotid);
					}else{
						js2.set(wokelock+robotid,1+"");
						js2.expire(wokelock+robotid,900);
					}

				}
			}


		}catch (Exception e) {
			e.printStackTrace();
		}finally {
			js2.close();
			js11.close();
		}


	}
	private String createGroupRoom(int groupId, int pid,int robotid) throws Exception {
		Jedis jedis0 = Redis.use("group1_db0").getJedis();
		try {

			GroupPlayBean gpb = GroupCache.getPlay(groupId, pid);
			if (gpb==null) {
				throw new WebException(ErrorCode.GROUP_PLAY_EXIST);
			}

			int gameId = gpb.gameId;
			GameBean gb = GameCache.getGame(gameId);

			String grooms_key = GroupCache.genRoomsKey(groupId);
			GroupBean group = GroupCache.getGroup(groupId);
			ITObject configData = TObject.newFromJsonData(gpb.config);
			int maxPlayers = gpb.maxPlayers;

			int opt = configData.getInt("opt");
			String owner_session = AccountCache.genKey(group.owner);

			int dissolve_opt = group.dissolve_opt;
			int kick_opt = group.kick_opt;

			String newRoomId = Redis.use("group1_db1").rpop("free_room");
			Redis.use("group1_db1").lpush("free_room", newRoomId);
			String room_key = "room:" + newRoomId;




			String svr = _getSvr(jedis0,gb);
			if (svr == null) {
				throw new WebException(ErrorCode.NO_SERVICE);
			}

			Integer pay = gb.pay.get("pay"+opt+"_"+maxPlayers);


			long time = System.currentTimeMillis() / 1000;
			Map<String, String> roomMap = new HashMap<String, String>();
			/**
			 * 玩家列表Seat映射
			 */
			roomMap.put("robot", "1");
			int robot_existTime = (int)((Math.random() + 0.5) * 40);
			roomMap.put("robot_existTime", robot_existTime + "");

			roomMap.put("id", newRoomId);
			roomMap.put("owner", owner_session);
			roomMap.put("svr", svr);
			roomMap.put("AA", "0");
			roomMap.put("pay", pay+"");
			roomMap.put("agent", "1");
			roomMap.put("group", groupId+"");
			roomMap.put("gpid", pid+"");
			roomMap.put("payer", group.owner+"");
			roomMap.put("maxPlayers", maxPlayers + "");
			roomMap.put("times", gb.opt.get(opt)+"");
			roomMap.put("opt", opt + "");
			roomMap.put("status", "0");
			roomMap.put("hpOnOff", gpb.hpOnOff+"");
			roomMap.put("rewardType", gpb.rewardType+"");
			roomMap.put("rewardValueType", gpb.rewardValueType+"");
			roomMap.put("xipai_rewardType", gpb.xipai_rewardType+"");
			roomMap.put("xipai_rewardValueType", gpb.xipai_rewardValueType+"");
			roomMap.put("dismiss_time", DISMISS_TIME[dissolve_opt-1]);
			roomMap.put("kick_time", KICK_TIME[kick_opt-1]);
			roomMap.put("hp_times",gpb.hp_times+"");
			if(gpb.hpOnOff == 1) {
				ITObject hpObj = TObject.newFromJsonData(gpb.hpConfig);
				if (hpObj.getInt("limitInRoom") != null) {
					roomMap.put("limitInRoom", hpObj.getInt("limitInRoom") + "");
				}
				configData.putTObject("hpData", hpObj);
			}

			configData.del("opt");
			configData.del("AA");
			roomMap.put("options", configData.toJson());
			roomMap.put("game", gameId + "");
			roomMap.put("open", "1");
			roomMap.put("round", "0");
			roomMap.put("create_time", time + "");
			roomMap.put("cache_ver", "1");




			List<Integer> seat_list = new ArrayList<>();
			List<Integer> player_list = new ArrayList<>();

			seat_list.add(1);
			player_list.add(robotid);

			roomMap.put("players", toTArray(player_list).toJson());
			roomMap.put("seats", toTArray(seat_list).toJson());


			jedis0.hmset(room_key, roomMap);

				/**
				 * pid    open    status     剩余空位
				 * 11      1       1          00
				 */
			Redis.use("group1_db11").zadd(grooms_key, pid*10000+1101, room_key);
			GroupPublisherService.addRoomEvt(groupId, newRoomId);
			//updateRedisMap(groupId, newRoomId, room_key, roomMap, maxPlayers);
			return room_key;
		} finally {
			jedis0.close();
		}
	}

	public int getRobot(int maxPlayers)
	{
		long freeRobotNum = Redis.use("group1_db1").scard("free_robot");
		if (freeRobotNum < maxPlayers)
		{
			long useRobotNum = Redis.use("group1_db1").scard("used_robot");
			if (useRobotNum >= 100)
			{
				logger.warn("robot not enough, cur used robot " + useRobotNum);
			}
			try {
				createRobot();
				freeRobotNum = Redis.use("group1_db1").scard("free_robot");
				if (freeRobotNum < maxPlayers)
				{
					logger.error("create robot failed............");
					return 0;
				}

			}
			catch (Exception e)
			{
				logger.error(e);
			}
		}

		try {
			while(freeRobotNum > 0)
			{
				String strRobotId = Redis.use("group1_db1").spop("free_robot");
				freeRobotNum = Redis.use("group1_db1").scard("free_robot");
				if (StringUtil.isEmpty(strRobotId))
				{
					createRobot();
					continue;
				}
				else {
					AccountBean acc_bean = AccountCache.getAccount(Integer.parseInt(strRobotId));
					if (acc_bean != null)
					{
						URL url = null;
						try {
							url = new URL(acc_bean.portrait);
							InputStream in = url.openStream();
							String jsonStr = inputStreamToString(in);
							String md5 = MD5.getInstance().getHash(jsonStr);
							if (md5.equals("787d66f3fdfa8df70795629c62a3a850") || md5.equals("f1fce77813a0fc9660c76d523813bb59") || md5.equals("d629ac346299c2640dfb6e8fd4232646") || md5.equals("1e76068afc60d7dcff851936b3c2b24b") )
							{
								//logger.info("will use robot:" + strRobotId + " head:" + acc_bean.portrait + " md5:" + md5);
								url = null;
							}
							//logger.info("will use robot:" + strRobotId + " head:" + acc_bean.portrait + " md5:" + md5);
						} catch (Exception e1) {
						    url = null;
						}
						if (url == null)
						{
							logger.error("robot head error, this robot:"+ strRobotId + " will not use");
							continue;
						}
					}
					else {
						continue;
					}
				}

				Redis.use("group1_db1").sadd("used_robot", strRobotId);
				int robotId = Integer.parseInt(strRobotId);
				String fakeHp = Redis.use("group1_db10").hget("fake_"+strRobotId, "fake_hp");
				if (StringUtil.isEmpty(fakeHp))
				{
					int fake_hp = (int)(Math.random() * 10000000);
					Redis.use("group1_db10").hset("fake_"+strRobotId, "fake_hp", Integer.toString(fake_hp));
				}
				return robotId;
			}
		}
		catch (Exception e)
		{
			logger.error(e);
		}
		return 0;
	}

	/**
	 * 登录
	 * @throws Exception
	 */
	public final void createRobot() throws Exception {
		int num = 100;
		int mng = 9999;

		String listSql = "select * from old_account";
		ITArray resultArray = DataBase.use().executeQueryByTArray(listSql);
		ArrayList<String> nameList = new ArrayList<>();
		ArrayList<String> headList = new ArrayList<>();
		for(int i = 0; i < resultArray.size(); i++)
		{
			ITObject userData = resultArray.getTObject(i);
			String nick = userData.getUtfString("nick");
			nameList.add(nick);
			String head = userData.getUtfString("portrait");
			headList.add(head);
		}

		Math.random();
		Collections.shuffle(nameList);
		Collections.shuffle(headList);

		for(int i = 0; i < num; i++)
		{
			String sql = "";
			int accountid = create_register(mng, "xx123456xx", nameList, headList);
			AccountBean acc_bean = AccountCache.getAccount(accountid);
			if (acc_bean == null)
			{
				sql  = String.format("SELECT * FROM account WHERE id ='%d'",
						accountid);

				ITArray resultArray2 = DataBase.use().executeQueryByTArray(sql);
				if(resultArray2.size() ==0) {
					throw new WebException(ErrorCode._FAILED);
				}

				ITObject userData = resultArray2.getTObject(0);
				UpdateUserData(userData, accountid);

				acc_bean = AccountCache.getAccount(accountid);
			}

			Redis.use("group1_db1").sadd("free_robot", Integer.toString(acc_bean.id));
			int fake_hp = (int)(Math.random() * 10000000);
			Redis.use("group1_db10").hset("fake_"+acc_bean.id, "fake_hp", Integer.toString(fake_hp));
		}
	}

	/**
	 *
	 * @return
	 * @throws Exception
	 */
	private final int UpdateUserData(ITObject reqData,long id) throws Exception {
		ITObject userData = TObject.newInstance();
		userData.putInt("id", (int)id);

		userData.putUtfString("acc", reqData.getUtfString("acc"));
		userData.putUtfString("portrait", reqData.getUtfString("portrait"));
		userData.putUtfString("nick", reqData.getUtfString("nick"));
		int sex = reqData.getInt("sex");
		if(sex == 0) {
			sex = 1;
			reqData.putInt("sex", sex);
		}
		userData.putInt("sex", sex);

		userData.putInt("mng", 0);
		userData.putInt("type", 0);
		if(reqData.containsKey("diamo")) {
			userData.putInt("diamo", reqData.getInt("diamo"));
		}

		userData.putInt("invitation", 1);
		updateSession(userData, (int) id);
		return (int)id;
	}


	private static String updateSession(ITObject userData, int id) {
		String session = AccountCache.genKey(id);
		Map<String, String> map = new HashMap<String, String>();
		Utils.objectToMap(userData, map);

		Jedis jedis0 = Redis.use("group1_db0").getJedis();
		try {
			jedis0.hmset(session, map);
			BaseCache.updateCacheVer(jedis0, session);
		}finally {
			jedis0.close();
		}

		return session;
	}


	/**
	 *
	 * @description: 将输入流转换成字符串
	 * @author: Jeff
	 * @date: 2019年12月15日
	 * @param inputStream 输入流
	 * @return
	 */
	private static String inputStreamToString(InputStream inputStream) {
		StringBuffer buffer = new StringBuffer();
		InputStreamReader inputStreamReader;
		try {
			inputStreamReader = new InputStreamReader(inputStream, "utf-8");
			BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
			String str = null;
			while ((str = bufferedReader.readLine()) != null) {
				buffer.append(str);
			}
			// 释放资源
			bufferedReader.close();
			inputStreamReader.close();
			inputStream.close();
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return buffer.toString();
	}

	private final int create_register(int mng, String password, ArrayList<String> nickList, ArrayList<String> headList) throws Exception {
		int count = 0;
		long id = 0;
		ArrayList<String> list = new ArrayList<>();
		for(int i = 0; i < 10; i++)
		{
			String strId = Redis.use("group1_db1").rpop("free_account");
			if (StringUtil.isEmpty(strId))
			{
				break;
			}
			list.add(strId);
		}
		//logger.info("free_account:"+list.toString());

		Collections.shuffle(list);

		do {
			id = Long.parseLong(list.remove(0));
			String sql = "SELECT id FROM account WHERE id =" + id;
			ITArray resultArray = DataBase.use().executeQueryByTArray(sql);
			if (resultArray.size() == 0)
			{
				break;
			}
		}while(count++ <= 10);

		for(int i = 0; i < list.size(); i++)
		{
			Redis.use("group1_db1").lpush("free_account", list.get(i));
		}

		if (id == 0)
		{
			throw new WebException(ErrorCode._FAILED);
		}

		ITObject userData = TObject.newInstance();
		userData.putInt("id", (int)id);

		userData.putUtfString("acc", "" + id);
		userData.putUtfString("portrait", "");
		while (headList.size() > 0)
		{
		    String head = null;
			try {
			    head = headList.remove(0);
				URL url = new URL(head);
				InputStream in = url.openStream();
				String jsonStr = inputStreamToString(in);
				String md5 = MD5.getInstance().getHash(jsonStr);
			//	logger.info("robot:" + id + " head:" + head + " md5:" + md5);
				if (md5.equals("787d66f3fdfa8df70795629c62a3a850") || md5.equals("f1fce77813a0fc9660c76d523813bb59") || md5.equals("d629ac346299c2640dfb6e8fd4232646") || md5.equals("1e76068afc60d7dcff851936b3c2b24b") )
				{
					head = null;
				}
			} catch (Exception e1) {
			    head = null;
			}
			if (head != null)
			{
				userData.putUtfString("portrait", head); //头像
                break;
			}
		}

		String nick = "";
		if (nickList.size() > 0)
		{
			nick = nickList.remove(0);
		}
		nick = nick.replaceAll("[^a-zA-Z0-9\\u4e00-\\u9fa5]", " ");
		userData.putUtfString("nick", nick);
		int sex = 1;
		if(sex == 0) {
			sex = 1;
		}
		userData.putInt("sex", sex);
		userData.putInt("diamo", 0);
		userData.putInt("mng", 0);
		userData.putInt("regTime", mng);
		userData.putInt("type", 0);
		userData.putUtfString("password",  Utils.getMD5Hash(password));
		long reg_time = System.currentTimeMillis() / 1000;
		userData.putLong("reg_time", reg_time);
		logger.info("create robot account:"+userData.toJson()+" password:" + password);
		int result = DataBase.use().insert("account", userData);
		if (result == -1) {
			throw new WebException(ErrorCode._FAILED);
		}
		userData.putInt("invitation", 1);
		String session = updateSession(userData, (int) id);
		return (int)id;
	}
}
