package com.palmnest.dao.hibernate;

import cn.superdesk.libs.common.json.JsonUtils;
import com.palmnest.application.bean.Page;
import com.palmnest.application.core.util.PasswordUtils;
import com.palmnest.application.core.util.StringUtil;
import com.palmnest.dao.UserDao;
import com.palmnest.model.*;
import com.palmnest.service.redis.BaseRedisService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.hibernate.Query;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.orm.hibernate4.SessionFactoryUtils;
import org.springframework.security.authentication.encoding.PasswordEncoder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.codec.Utf8;
import org.springframework.stereotype.Repository;
import org.springframework.util.CollectionUtils;
import scala.annotation.meta.param;

import javax.persistence.Table;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Base64;
import java.util.List;
import java.util.Map;

/**
 * This class interacts with Hibernate session to save/delete and retrieve User
 * objects.
 *
 * @author <a href="mailto:chasel.java@gmail.com">Chasel Li</a>
 */
@Slf4j
@Repository("userDao")
public class UserDaoHibernate extends GenericDaoHibernate<User, Long> implements
		UserDao, UserDetailsService {

	@Autowired
	private BaseRedisService baseRedisService;

	/**
	 * Constructor that sets the entity to User.class.
	 */
	public UserDaoHibernate() {
		super(User.class);
	}

	/**
	 * {@inheritDoc}
	 */
	@SuppressWarnings("unchecked")
	public List<User> getUsers() {
		Query qry = getSession().createQuery(
				"from User u order by upper(u.username)");
		return qry.list();
	}

	/**
	 * {@inheritDoc}
	 */
	public User saveUser(User user) {
		if (log.isDebugEnabled()) {
			log.debug("user's id: " + user.getId());
		}
		if (user.getId() != null) {
			getSession().merge(user);
		} else {
			getSession().save(user);
		}
		/*// necessary to throw a DataIntegrityViolation and catch it in
		// UserManager
		getSession().flush();*/
		return user;
	}

	/**
	 * Overridden simply to call the saveUser method. This is happening because
	 * saveUser flushes the session and saveObject of BaseDaoHibernate does not.
	 *
	 * @param user the user to save
	 * @return the modified user (with a primary key set if they're new)
	 */
	@Override
	public User save(User user) {
		return this.saveUser(user);
	}

	/**
	 * {@inheritDoc}
	 */
	@SuppressWarnings("rawtypes")
	public UserDetails loadUserByUsername(String username)
			throws UsernameNotFoundException {

		if(StringUtils.isEmpty(username)){
			throw new UsernameNotFoundException("username is empty.");
		}
		//List users = getSession().createCriteria(User.class).add(Restrictions.eq("username", username)).add(Restrictions.eq("isenabled", "1")) .list();
		String token = "";
		log.info("loadUserByUsername-username:{}",username);
		if(StringUtils.isNotEmpty(username) && username.indexOf("token") != -1 && username.indexOf("!") != -1){
			String []  arr = username.split("!");
			token = arr[1];
			log.info("loadUserByUsername-token:{}",token);
			if(StringUtils.isNotEmpty(token)){
				String name = baseRedisService.get(token);
				if(StringUtils.isNotEmpty(name)){
					username = name;
					log.info("loadUserByUsername-username2:{}",username);
				}
			}
		}else{
			log.info("loadUserByUsername进来了这里");
			throw new UsernameNotFoundException("user '" + username
					+ "' not found...");
		}
		String     strHql = "from User where (username=? or telephone=?) and   isenabled=1";
		List<User> users  = getSession().createQuery(strHql).setString(0, username).setString(1, username).list();

		if (users == null || users.isEmpty()) {
			throw new UsernameNotFoundException("user '" + username
					+ "' not found...");
		} else {
			UserDetails details = users.get(0);
			if(StringUtils.isNotEmpty(token)){
				String ecodeStr = PasswordUtils.encodePassword(token, username);
				log.info("ecodeStr:{}",ecodeStr);
				((User) details).setPassword(ecodeStr);
			}
			log.info("details2:{}", JsonUtils.toJson(details));
			return details;
		}
	}



	public static void main(String[] args) {
		String username = "token!88a5a912ab4647fea6f6da52773bbedf";
		String []  arr = username.split("!");
		String token = arr[1];
		System.out.println(token);
		String a = URLEncoder.encode("username");
	}

	/**
	 * {@inheritDoc}
	 */
	public String getUserPassword(Long userId) {
		JdbcTemplate jdbcTemplate = new JdbcTemplate(
				SessionFactoryUtils.getDataSource(getSessionFactory()));
		Table table = AnnotationUtils.findAnnotation(User.class, Table.class);
		return jdbcTemplate.queryForObject(
				"select password from " + table.name() + " where id=?",
				String.class, userId);
	}

	@Override
	public User getUserByUsername2(String username) {
		String     strHql = "from User where (username=? or telephone=?) and isenabled=1";
		List<User> users  = getSession().createQuery(strHql).setString(0, username).setString(1,username).list();
		if (users == null || users.isEmpty()) {
			return null;
		} else {
			return (User) users.get(0);
		}
	}

	public Page queryUserPage(int pageNo, int pageSize, String strSQL) {
		return pagedQueryByJdbcTemplate(strSQL, pageNo, pageSize);
	}

	@Override
	public void updateUser(User user) {
		getSession().update(user);
	}

	public User getUser(String username, String password) {
		String     strHql = "from User where username=? and password=? and isenabled=1";
		List<User> users  = getSession().createQuery(strHql).setString(0, username).setString(1, password).list();
		if (CollectionUtils.isEmpty(users)) {
			return null;
		} else {
			return users.get(0);
		}
	}


	@Override
	public List<AppUserOrgnizationRelation> getAppUserOrgByUserId(int userid) {
		String                           strHql = "from AppUserOrgnizationRelation where userId=?";
		List<AppUserOrgnizationRelation> list   = getSession().createQuery(strHql).setInteger(0, userid).list();
		return list;
	}

//	@Override
//	public List<AppUserOrgRelation> getAppUserOrgByUserId(int userid) {
//		String strHql="from AppUserOrgRelation where userId=?";
//		List<AppUserOrgRelation> list=getSession().createQuery(strHql).setInteger(0, userid).list();
//		return list;
//	}

	@Override
	public List<AppUserCompanyRelation> getAppUserCompanyByUserId(int userid) {
		String                       strHql = "from AppUserCompanyRelation where userId=?";
		List<AppUserCompanyRelation> list   = getSession().createQuery(strHql).setInteger(0, userid).list();
		return list;
	}

	@Override
	public List<AppUserOrgnizationRelation> getUserOrgByUserId(Long userid) {
		String                           strHql = "from AppUserOrgnizationRelation where userId=?";
		List<AppUserOrgnizationRelation> list   = getSession().createQuery(strHql).setLong(0, userid).list();
		return list;
	}

	@Override
	public List<AppUserFloorRelation> getAppUserFloorByUserId(int userid) {
		String                     strHql = "from AppUserFloorRelation where user_id=?";
		List<AppUserFloorRelation> list   = getSession().createQuery(strHql).setInteger(0, userid).list();
		return list;
	}

//	@Override
//	public List<AppUserOrgRelation> getAppUserOrgByUserId(int userid,String type) {
//		String strHql="from AppUserOrgRelation where userId=? and orgType=?";
//		List<AppUserOrgRelation> list=getSession().createQuery(strHql).setInteger(0, userid).setString(1, type).list();
//		return list;
//	}

//	@Override
//	public void deleteAppUserOrgByUserId(int userid, String orgType) {
//		String strHql="delete from AppUserOrgRelation where userId=? and orgType=?";
//		getSession().createQuery(strHql).setInteger(0, userid).setString(1, orgType).executeUpdate();
//	}

	@Override
	public void deleteAppUserOrgByUserId(Long userid) {
		String strHql = "delete from AppUserOrgnizationRelation where userId=? ";
		getSession().createQuery(strHql).setLong(0, userid).executeUpdate();
	}

	@Override
	public void deleteAppUserFloorByUserId(int userid, String orgType) {
		String strHql = "delete from AppUserFloorRelation where user_id=? ";
		getSession().createQuery(strHql).setInteger(0, userid).executeUpdate();
	}

//	@Override
//	public void deleteAppUserOrgByOrgId(int orgid, String orgType) {
//		String strHql="delete from AppUserOrgRelation where orgId=? and orgType=?";
//		getSession().createQuery(strHql).setInteger(0, orgid).setString(1, orgType).executeUpdate();
//	}

//	@Override
//	public void saveAppUserOrgRelation(AppUserOrgRelation model) {
//		getSession().save(model);
//	}

	@Override
	public void saveAppUserOrgRelation(AppUserOrgnizationRelation model) {
		getSession().save(model);
	}

	@Override
	public void saveAppUserOrgRelation(AppUserFloorRelation model) {
		getSession().save(model);
	}


	@Override
	public List<User> findByFunction(String systemCode) {
		String sql = "SELECT DISTINCT au.* FROM tb_app_function ap " +
				" JOIN tr_app_role_function arf ON ap.id=arf.function_id " +
				" JOIN tb_app_role ar ON arf.roleid = ar.id " +
				" JOIN tr_app_user_role  aur ON aur.role_id=ar.id " +
				" JOIN tb_app_user au ON aur.user_id = au.id " +
				" WHERE au.ISENABLED=1 and ap.systemcode = " + systemCode;
		//return (ArrayList<User>) getSession().createSQLQuery(sql).addEntity(User.class).list();
		List<User> users = (ArrayList<User>) getSession().createSQLQuery(sql).addEntity(User.class).list();
		return users;
	}


	/**
	 * 后台保存更新系统更新通知时更新后台用户通知状态
	 */
	@Override
	public void updateAllState() {
		String sql = " update tb_app_user set ERRORNUM=0";
		getSession().createSQLQuery(sql).executeUpdate();
	}

	@Override
	public ArrayList<User> getUserByType(int type) {
		String strHql = "from User where deviceType =? AND  deviceNo is not null";
		return (ArrayList<User>) getSession().createQuery(strHql).setInteger(0, type).list();
	}

	@Override
	public List<User> findByFunction(Integer orgId, String systemCode) {
		String sql = "SELECT DISTINCT au.* " +
				"	FROM tb_app_function ap " +
				" 		JOIN tr_app_role_function arf ON ap.id=arf.function_id " +
				" 		JOIN tb_app_role ar ON arf.roleid = ar.id " +
				" 		JOIN tr_app_user_role  aur ON aur.role_id=ar.id " +
				" 		JOIN tb_app_user au ON aur.user_id = au.id " +
				" 		left join tr_app_user_orgnization tauo ON tauo.user_id=au.id " +
				" WHERE " +
				"		au.ISENABLED=1 " +
				" 		and au.USERNAME<>'admin'" +
				"		and ap.systemcode = " + systemCode +
				"		and tauo.org_id=" + orgId + " ";
		//return (ArrayList<User>) getSession().createSQLQuery(sql).addEntity(User.class).list();
		List<User> users = (ArrayList<User>) getSession().createSQLQuery(sql).addEntity(User.class).list();
		return users;
	}


	/**
	 * 只过滤普通人员的
	 * 空调开关人员过滤
	 *
	 * @param orgId
	 * @param systemCode
	 * @return
	 */
	@Override
	public List<User> findByFunctionGeneral(Integer orgId, String systemCode) {
		String sql = "SELECT DISTINCT au.* FROM tb_app_function ap " +
				" JOIN tr_app_role_function arf ON ap.id=arf.function_id " +
				" JOIN tb_app_role ar ON arf.roleid = ar.id " +
				" JOIN tr_app_user_role  aur ON aur.role_id=ar.id " +
				" JOIN tb_app_user au ON aur.user_id = au.id " +
				" WHERE au.ISENABLED=1 AND au.USER_TYPE = 4 and ar.ORG_ID='" + orgId + "' and ap.systemcode = " + systemCode;
		//return (ArrayList<User>) getSession().createSQLQuery(sql).addEntity(User.class).list();
		List<User> users = (ArrayList<User>) getSession().createSQLQuery(sql).addEntity(User.class).list();
		return users;
	}

	@Override
	public List<User> findByRoleId(Integer roleId,Integer orgId) {
		String     sql   = "  SELECT t1.* FROM tb_app_user t1 LEFT JOIN tr_app_user_role t2 ON t1.ID = t2.USER_ID " +
							" LEFT JOIN tb_app_role t3 ON t2.ROLE_ID = t3.ID " +
							" LEFT JOIN tr_app_user_orgnization org on org.user_id = t1.ID " +
							" WHERE t3.ID = " + roleId +
		                    " AND org.org_id = " + orgId;
		List<User> users = (ArrayList<User>) getSession().createSQLQuery(sql).addEntity(User.class).list();
		return users;
	}

	@Override
	public User findByFunctionAndUser(String systemCode, Long userId) {
		String sql = "SELECT DISTINCT au.* FROM tb_app_function ap " +
				" JOIN tr_app_role_function arf ON ap.id=arf.function_id " +
				" JOIN tb_app_role ar ON arf.roleid = ar.id " +
				" JOIN tr_app_user_role  aur ON aur.role_id=ar.id " +
				" JOIN tb_app_user au ON aur.user_id = au.id " +
				" WHERE au.ISENABLED=1 and ap.systemcode = " + systemCode +
				" and au.id = " + userId;
		List<User> users = (ArrayList<User>) getSession().createSQLQuery(sql).addEntity(User.class).list();
		if (users.size() > 0) {
			return users.get(0);
		}
		return null;
	}

	@Override
	public List<User> findByFunctionAndUserList(String systemCode, Long userId) {
		String sql = "SELECT DISTINCT au.* FROM tb_app_function ap " +
				" JOIN tr_app_role_function arf ON ap.id=arf.function_id " +
				" JOIN tb_app_role ar ON arf.roleid = ar.id " +
				" JOIN tr_app_user_role  aur ON aur.role_id=ar.id " +
				" JOIN tb_app_user au ON aur.user_id = au.id " +
				" WHERE au.ISENABLED=1 and ap.systemcode = " + systemCode +
				" and au.id = " + userId;
		List<User> users = (ArrayList<User>) getSession().createSQLQuery(sql).addEntity(User.class).list();
		return users;
	}

	/*
	 * 查询会议室审核角色
	 * 只查项目管理员及普通管理员对应角色
	 */
	@Override
	public List<Map<String, Object>> findMeetingAuditRoleByOrdId(String OrdId) {
		String sql = " select DISTINCT ar.ID,ar.`NAME`  " +
				" from tb_app_role ar " +
				" left join tr_app_role_function arf on ar.id=arf.roleid " +
				" left join tb_app_function ap on ap.id=arf.FUNCTION_ID " +
				" where ap.systemcode = 8010 and ar.ROLE_TYPE>=3 and ar.ORG_ID=" + OrdId +
				" order by  ar.ID ";

		return getJdbcTemplate().queryForList(sql.toString());
	}


	@Override
	public Role findRoleByFunctionAndUser(String systemCode, Long userId) {
		String sql = "SELECT DISTINCT ar.* FROM tb_app_function ap " +
				" JOIN tr_app_role_function arf ON ap.id=arf.function_id " +
				" JOIN tb_app_role ar ON arf.roleid = ar.id " +
				" JOIN tr_app_user_role  aur ON aur.role_id=ar.id " +
				" JOIN tb_app_user au ON aur.user_id = au.id " +
				" WHERE au.ISENABLED=1 and ap.systemcode = " + systemCode +
				" and au.id = " + userId;
		List<Role> roles = (ArrayList<Role>) getSession().createSQLQuery(sql).addEntity(Role.class).list();
		if (roles.size() > 0) {
			return roles.get(0);
		}
		return null;
	}

	@Override
	public List<Role> findRoleBySystemCodeAndRoleIds(String systemCode, String roleIds) {
		String sql = "SELECT DISTINCT ar.* FROM tb_app_function ap " +
				" JOIN tr_app_role_function arf ON ap.id=arf.function_id " +
				" JOIN tb_app_role ar ON arf.roleid = ar.id " +
				" WHERE ar.ROLE_TYPE>=3 and ap.systemcode = " + systemCode +
				" and ar.id in " + "(" + roleIds + ")";

		List<Role> roles = (ArrayList<Role>) getSession().createSQLQuery(sql).addEntity(Role.class).list();

		return roles;
	}


	@Override
	public User findByTelephone(String telephone) {
		String strHql = "from User where telephone=? and (isenabled=1 or isenabled is null)";
		User   user   = (User) getSession().createQuery(strHql).setString(0, telephone).uniqueResult();
		return user;
	}

	@Override
	public List<User> queryUserBySql(String querySql) {

		List<User> users = getSession().createQuery(querySql).list();

		return users;
	}

	@Override
	public List<AppUserFloorRelation> getAppUserFloorByUserId(int userid, int roleId) {
		String                     strHql = "from AppUserFloorRelation where user_id=? and role_id=? order by floor_id ";//简单排序
		List<AppUserFloorRelation> list   = getSession().createQuery(strHql).setInteger(0, userid).setInteger(1, roleId).list();
		return list;
	}

	@Override
	public List<Map<String, Object>> getPower(String orgId, int sysCode) {
		StringBuilder sql = new StringBuilder(" select DISTINCT us.device_type deviceType,us.device_no deviceNo,us.id usId,us.FULL_NAME userName,us.TELEPHONE userTel,fuc.SYSTEMCODE fucCode,fuc.FUNCTION_NAME fucName from tb_app_user us");
		sql.append(" left join tr_app_user_role ur on us.id=ur.USER_ID ");
		sql.append(" left join tb_app_role rl on rl.id=ur.role_id ");
		sql.append(" left join tr_app_role_function fu on fu.ROLEID=ur.ROLE_ID ");
		sql.append(" left join tb_app_function fuc on fuc.id=fu.FUNCTION_ID ");
		sql.append(" left join tr_app_user_floor uf on uf.user_id=us.id ");
		sql.append(" where us.ISENABLED='1' and fuc.SYSTEMCODE=" + sysCode);
		sql.append(" and us.USERNAME<>'admin' ");
		if (StringUtils.isNotEmpty(orgId)) {
			sql.append(" and rl.ORG_ID=" + orgId);
		}

		return getJdbcTemplate().queryForList(sql.toString());
	}

	@Override
	public List<Map<String, Object>> getPowerByOrgIds(String orgIds, int sysCode) {
		StringBuilder sql = new StringBuilder(" select DISTINCT us.device_type deviceType,us.device_no deviceNo,us.id usId,us.FULL_NAME userName,us.TELEPHONE userTel,fuc.SYSTEMCODE fucCode,fuc.FUNCTION_NAME fucName from tb_app_user us");
		sql.append(" left join tr_app_user_role ur on us.id=ur.USER_ID ");
		sql.append(" left join tb_app_role rl on rl.id=ur.role_id ");
		sql.append(" left join tr_app_role_function fu on fu.ROLEID=ur.ROLE_ID ");
		sql.append(" left join tb_app_function fuc on fuc.id=fu.FUNCTION_ID ");
		sql.append(" left join tr_app_user_floor uf on uf.user_id=us.id ");
		sql.append(" where us.ISENABLED='1' and fuc.SYSTEMCODE=" + sysCode);
		sql.append(" and us.USERNAME<>'admin' and us.TELEPHONE is not null ");
		sql.append(" and us.USER_TYPE=4 ");
		if (StringUtils.isNotEmpty(orgIds)) {
			sql.append(" and rl.ORG_ID in (" + orgIds + " ) ");
		}
		return getJdbcTemplate().queryForList(sql.toString());
	}


	@Override
	public List<User> findByFunAndRoleAndFloor(String systemCode, String floorId) {//and ar.id='"+roleId+"'
		String sql = "SELECT DISTINCT au.* FROM tb_app_function ap " +
				" JOIN tr_app_role_function arf ON ap.id=arf.function_id " +
				" JOIN tb_app_role ar ON arf.roleid = ar.id " +
				" JOIN tr_app_user_role  aur ON aur.role_id=ar.id " +
				" JOIN tb_app_user au ON aur.user_id = au.id " +
				" left JOIN tr_app_user_floor fl on (au.id= fl.user_id and fl.role_id=ar.id) " +
				" WHERE au.ISENABLED=1  and ap.systemcode = " + systemCode + " and fl.floor_id=" + floorId;
		//return (ArrayList<User>) getSession().createSQLQuery(sql).addEntity(User.class).list();
		List<User> users = (ArrayList<User>) getSession().createSQLQuery(sql).addEntity(User.class).list();
		return users;
	}

}
