package com.sf.apijson.config;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.util.ArrayList;
import java.util.List;

import javax.servlet.http.HttpSession;
import javax.sql.DataSource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.sf.common.core.domain.entity.SysUser;
import com.sf.common.utils.spring.SpringUtils;
import com.sf.framework.web.service.PermissionService;

import apijson.JSONResponse;
import apijson.NotNull;
import apijson.RequestMethod;
import apijson.StringUtil;
import apijson.framework.APIJSONConstant;
import apijson.framework.APIJSONFunctionParser;
import apijson.router.APIJSONRouterVerifier;

@Component
public class FormFunctionParser extends APIJSONFunctionParser {
	private static final Logger log = LoggerFactory.getLogger(FormFunctionParser.class);
	public static final String APIJSON_ALL_INIT_REDIS_KEY = "apijson:all:init";

	//@Autowired
	//private IShowLogService showLogService;

	public FormFunctionParser() {
		this(null, null, 0, null, null);
	}

	// 展示在远程函数内部可以用 this 拿到的东西
	public FormFunctionParser(RequestMethod method, String tag, int version, JSONObject request, HttpSession session) {
		super(method, tag, version, request, session);
	}

	/***
	 * 获取当前用户id
	 * 
	 * @param current
	 * @return
	 * @throws Exception
	 */
	public String getCurrentUserId(@NotNull JSONObject current) throws IllegalAccessException {
		if (this.getSession() == null) {
			return "test"; // 启动时的自动测试
		}
		String uid = (String) this.getSession().getAttribute(APIJSONConstant.VISITOR_ID);
		if (uid == null) {
			throw new IllegalAccessException("user not logged in");
		}
		// return FormVerifier.getVisitorId(getSession());
		return uid;
	}

	/***
	 * 测试spring方法,事物
	 * @param current
	 * @param id
	 */
	public void callSpringService(@NotNull JSONObject current, @NotNull String id) {
		if (this.getSession() == null) {
			return; // 启动时的自动测试
		}
		// 测试service
		//ShowLog showLog = showLogService.selectShowLogById(current.getString(id));
		//log.info(JSONObject.toJSONString(showLog));
		// 测试spring事物
		//showLogService.testApijsonTrans();
	}
	
	/***
	 * 调用apijson router
	 */
	public void callRouter(@NotNull JSONObject current) {
		if (this.getSession() == null) {
			return; // 启动时的自动测试
		}
		// router get
		JSONObject routerMap = new JSONObject();
		routerMap.put("pageNum", 1);
		routerMap.put("pageSize", 10);
		String routerResponse = APIJSONRouterExecuter.execute(RequestMethod.GET, "Logback1708937338000list", null, routerMap.toJSONString(), getSession());
		log.info("routerResponse:{}", routerResponse);
	}

	/***
	 * 测试事物
	 * @throws Exception 
	 */
	public void testTransactional(@NotNull JSONObject current) throws Exception {
		if (this.getSession() == null) {
			return; // 启动时的自动测试
		}
		//spring service事务
		//activityRaffleLogService.sayHello();
		
		// 不支持事物
		String tableName = "Document_copy2";
		String postJsonStr = "{\n"
				+ "        \"userId\": \"1\",\n"
				+ "        \"testAccountId\": 1,\n"
				+ "        \"version\": 1,\n"
				+ "        \"name\": \"test\",\n"
				+ "        \"type\": \"JSON\",\n"
				+ "        \"url\": \"/router/get/Document1169"+System.currentTimeMillis()+"list\",\n"
				+ "        \"request\": \"{}\"\n"
				+ "    }";
//		JSONObject result = new FormParser(RequestMethod.POST, false).parseResponse(postJsonStr);
//		log.info(result.toJSONString());
		
		// url必须是非public请求,才支持事物
//		JSONObject postJson = JSONObject.parseObject(postJsonStr);
//		JSONObject response =  this.getObjectParser().setMethod(RequestMethod.POST).onObjectParse(postJson, null, tableName, null, false);
//		log.info("response:{}",response);
		
		//修改
//		String putJsonStr = "{\n"
//				+ "\"id\": 261,\n"
//				+ "\"name\": \"角色2\"\n"
//				+ "}";
//		JSONObject putJson = JSONObject.parseObject(putJsonStr);
//		JSONObject response =  this.getObjectParser().setMethod(RequestMethod.PUT).onObjectParse(putJson, null, tableName, null, false);
//		log.info("response:{}",response);
		
		//删除
		String delJsonStr = "{\n"
				+ "        \"id{}\": [\n"
				+ "            264\n"
				+ "        ]\n"
				+ "    }";
		JSONObject delJson = JSONObject.parseObject(delJsonStr);
		JSONObject response =  this.getParser().setMethod(RequestMethod.DELETE).onObjectParse(delJson, null, tableName, null, false);
		log.info("response:{}",response);
		int i = 2/0;
		
	}
	
	/***
	 * apijson事物
	 */
	public void transApijson() {
		
	}
	
	/***
	 * 业务方法事物
	 */
	public void transBuss() {
		
	}

	/***
	 * 普通用户返回id， admin返回null
	 * 
	 * @param current
	 * @return
	 * @throws IllegalAccessException
	 */
	public String getCurrentUserIdOrAdmin(@NotNull JSONObject current, @NotNull String paramKey, @NotNull String delKey)
			throws IllegalAccessException {
		if (this.getSession() == null) {
			return "test"; // 启动时的自动测试
		}
		String uid = (String) this.getSession().getAttribute(APIJSONConstant.VISITOR_ID);
		if (SysUser.isAdmin(Long.valueOf(uid))) {
			// 删除参数，查询全部数据
			// 普通用户查询语句兼容
			JSONObject parent = current;
			String[] pathKeys = delKey.split("\\.");
			if (pathKeys.length == 0) {
				current.remove(pathKeys[0]);
			} else {
				// 逐层到达child的直接容器JSONObject parent
				JSONObject p = null;
				for (int i = 0; i < pathKeys.length; i++) {// 一步一步到达指定位置
					if (i == 0) {
						p = parent.getJSONObject(pathKeys[i].trim());
					} else if (i != pathKeys.length - 1) {
						p = p.getJSONObject(pathKeys[i].trim());
					} else {
						p.remove(pathKeys[pathKeys.length - 1]);
						current.remove(paramKey);
						return null;
					}
				}
			}
		}
		return uid;
	}

	/**
	 * 一个最简单的远程函数示例，返回一个前面拼接了 Hello 的字符串
	 * 
	 * @param current
	 * @param name
	 * @return
	 * @throws Exception
	 */
	public String sayHello(@NotNull JSONObject current, @NotNull String name) throws Exception {
		// 注意这里参数 name 是 key，不是 value
		Object obj = current.get(name);

		if (this.getSession() == null) {
			return "test"; // 启动时的自动测试
		}

		if (obj == null) {
			throw new IllegalArgumentException();
		}
		if (!(obj instanceof String)) {
			throw new IllegalArgumentException();
		}

		// 之后可以用 this.getSession 拿到当前的 HttpSession
		return "Hello, " + obj.toString();
	}

	public String functionToUrl(@NotNull JSONObject current, @NotNull String name) throws Exception {
		if (this.getSession() == null) {
			return "test"; // 启动时的自动测试
		}
		// 注意这里参数 name 是 key，不是 value
		Object obj = current.get(name);
		if (obj == null) {
			throw new IllegalArgumentException();
		}
		if (!(obj instanceof String)) {
			throw new IllegalArgumentException();
		}

		// 之后可以用 this.getSession 拿到当前的 HttpSession
		return "Hello, " + obj.toString();
	}

	/***
	 * 只开放GET请求 原始sql统计查询
	 */
	public Object rawSQL(@NotNull JSONObject current, @NotNull String paramName) {
		if (this.getSession() == null) {
			return "test"; // 启动时的自动测试
		}
		String key = APIJSONRouterVerifier.getCacheKeyForRequest(this.getMethod().name().toLowerCase(),
				current.getString("request_tag"));
		JSONObject document = APIJSONRouterVerifier.DOCUMENT_MAP.get(key) != null
				? APIJSONRouterVerifier.DOCUMENT_MAP.get(key).get(this.getVersion()) != null
						? APIJSONRouterVerifier.DOCUMENT_MAP.get(key).get(this.getVersion())
						: null
				: null;
		String sqlauto = document.getString("sqlauto");
		return buildSearchData(current, sqlauto, paramName);
	}

	private Object buildSearchData(JSONObject current, String sqlauto, String paramName) {
		Connection connection = null;
		PreparedStatement ps = null;
		ResultSet rs = null;
		try {
			DataSource ds = SpringUtils.getBean(DataSource.class);
			connection = ds.getConnection();
			// 执行预编译查询
			ps = connection.prepareStatement(sqlauto);
			JSONArray jr = current.getJSONArray(paramName);
			for (int i = 1; i <= jr.size(); i++) {
				Object psValue = current.get(jr.get(i - 1)) == null ? null : current.get(jr.get(i - 1));
				if (psValue == null) {
					throw new IllegalAccessException("request 参数 " + jr.get(i) + " 不存在! ");
				}
				ps.setObject(i, psValue);
			}
			rs = ps.executeQuery();
			ResultSetMetaData rsmd = rs.getMetaData();
			final int length = rsmd.getColumnCount();
			List<JSONObject> rsData = new ArrayList<>();
			while (rs.next()) {
				JSONObject rowData = new JSONObject();
				for (int i = 1; i <= length; i++) {
//					if (AbstractParser.PUBLIC_RETURN_COLUMN_TOCAMELCASE) {
//						rowData.put(StringUtil.toCamelCase(rsmd.getColumnLabel(i)), rs.getObject(i));
//					} else {
					rowData.put(rsmd.getColumnLabel(i), rs.getObject(i));
//					}
				}
				rsData.add(rowData);
			}
			// 组装返回数据
			return rsData;
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if (rs != null) {
				try {
					rs.close();
				} catch (Exception e) {
				}
			}

			if (ps != null) {
				try {
					ps.close();
				} catch (Exception e) {
				}
			}

			if (connection != null) {
				try {
					connection.close();
				} catch (Exception e) {
				}
			}
		}
		return null;
	}

	/***
	 * 业务表-插入不同表1:n <br/>
	 * 业务表-批量修改不同表1:n <br/>
	 * 测试 子表 前置函数调用,修改值是否成果 <br/>
	 * user_address 表 addr字段
	 * 
	 * @param current
	 * @param password
	 * @return
	 * @throws Exception
	 */
	public void childFunTest(@NotNull JSONObject current, @NotNull String addr) throws Exception {
		String c_addr = current.getString(addr);
		current.put(addr, c_addr + "_" + System.currentTimeMillis());
	}

	/***
	 * 兼容数组 和 ;分隔字符串
	 * 
	 * @param current
	 * @param keys
	 */
	public void removeKeys(@NotNull JSONObject current, String keys) {
		if (this.getSession() == null) {
			return; // 启动时的自动测试
		}
		// 默认参数;分隔
		String[] ks = StringUtil.split(keys, ";"); // 用分号 ; 分割
		// 根据 ks remove 掉 current 里的字段
		for (int i = 0; i < ks.length; i++) {
			// 删除Request数组对应的key
			boolean vertifyArrayKey = current.containsKey(ks[i]) && current.get(ks[i]) instanceof JSONArray ? true
					: false;
			if (vertifyArrayKey) {
				for (int j = 0; j < current.getJSONArray(ks[i]).size(); j++) {
					current.remove(current.getJSONArray(ks[i]).get(j));
				}
			}
			current.remove(ks[i]);
		}

		for (String key : current.keySet()) {
			if (key.startsWith("@") || key.endsWith("@")) {
				current.remove(key);
			}
		}
	}

	/***
	 * 全量初始化apijson配置
	 * 
	 * @param current
	 * @throws Exception
	 */
	public void allInitApijsonConfig(@NotNull JSONObject current) throws Exception {
		if (this.getSession() == null) {
			return; // 启动时的自动测试
		}

		String perm = "system:apijson:all:init";
		PermissionService permissionService = SpringUtils.getBean("ss", PermissionService.class);
		if (permissionService.hasPermi(perm) == false) {
			// 仅具有ROLE_ADMIN权限的用户可访问的逻辑
			throw new IllegalArgumentException("没有权限，请联系管理员授权");
		}

		StringRedisTemplate stringRedisTemplate = SpringUtils.getBean("stringRedisTemplate", StringRedisTemplate.class);
		try {
			// 分布式锁，防止重复提交
			Boolean lock = stringRedisTemplate.opsForValue().setIfAbsent(APIJSON_ALL_INIT_REDIS_KEY, "lock");
			if (!lock) {
				log.info("初始化动态表单，Redis加锁失败");
				throw new IllegalAccessException("初始化动态表单，Redis加锁失败");
			}
			// 全量更新
			ApijsonInitUtil.init();
		} finally {
			stringRedisTemplate.delete(APIJSON_ALL_INIT_REDIS_KEY);
		}
	}

	/***
	 * 增量初始化apijson配置
	 * 
	 * @param current
	 * @param tableName
	 * @param id
	 * @throws Exception
	 */
	public void addInitApijsonConfig(@NotNull JSONObject current, String tableName, String id) throws Exception {
		if (this.getSession() == null) {
			return; // 启动时的自动测试
		}

		String perm = "system:apijson:add:init";
		PermissionService permissionService = SpringUtils.getBean("ss", PermissionService.class);
		if (permissionService.hasPermi(perm) == false) {
			// 仅具有ROLE_ADMIN权限的用户可访问的逻辑
			throw new IllegalArgumentException("没有权限，请联系管理员授权");
		}

		JSONResponse responseJson = new JSONResponse(current);
		Long idVal = null;
		if (responseJson.get("code") == null || responseJson.isSuccess()) {
			if (this.getSession() == null) {
				return; // 启动时的自动测试
			}
			switch (tableName) {
			case "access":
				idVal = current.getLong(id);
				ApijsonInitUtil.addInitAccess(idVal);
				break;
			case "function":
				idVal = current.getLong(id);
				ApijsonInitUtil.addInitFunction(idVal);
				break;
			case "document":
				idVal = current.getLong(id);
				ApijsonInitUtil.addInitDocument(idVal);
				break;
			case "request":
				idVal = current.getLong(id);
				ApijsonInitUtil.addInitRequest(idVal);
				break;
			default:
				break;
			}
		}
	}
}
