package controller.rest;

import java.io.IOException;
import java.lang.reflect.Field;
import java.security.Principal;
import java.sql.CallableStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Random;

import javax.net.ssl.SSLEngineResult.Status;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.log4j.Logger;
import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
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.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import bean.AppVariables;
import bean.LoginUserBean;
import bean.SecurityLogUserBean;
import bean.UserInfoBean;
import bean.UserRoleBean;
import bean.filters.DistinteFilterBean;
import common.bean.UserBean;
import common.bean.UserData;
import common.controller.BaseController;
import dao.ApCabDao;
import dao.CondizioniCtrlDAO;
import dao.UserDAO;
import sicura.entities.Utenti;

@Controller
@RequestMapping("user")
public class UserRestController extends BaseController {

	@Autowired
	UserDAO userDAO;

	@RequestMapping(value="/userinfo",method=RequestMethod.GET) 
	@ResponseBody
	private UserInfoBean getUserInfo(HttpServletRequest request) {
		setRequest(request);
		
		UserInfoBean uib = new UserInfoBean();
		List<UserRoleBean> gruppi = new ArrayList<UserRoleBean>();
		 
		if(request.getRemoteUser()==null) {
			uib.setLogin("TR");
			gruppi.add(new UserRoleBean("TR","Tesoriere responsabile"));
			gruppi.add(new UserRoleBean("AS","Amministratore di sistema"));
			gruppi.add(new UserRoleBean("GI","Gestore informatico"));
			gruppi.add(new UserRoleBean("DF", "Delegato alla firma"));
			gruppi.add(new UserRoleBean("VI", "Utente visualizzatore"));
		} else {
		
			uib.setLogin(request.getRemoteUser());
			
			if (request.isUserInRole("SicuraWeb_TR"))
				gruppi.add(new UserRoleBean("TR","Tesoriere responsabile"));
			if (request.isUserInRole("SicuraWeb_AS"))
				gruppi.add(new UserRoleBean("AS","Amministratore di sistema"));
			if (request.isUserInRole("SicuraWeb_GI"))
				gruppi.add(new UserRoleBean("GI","Gestore informatico"));
			if (request.isUserInRole("SicuraWeb_DF"))
				gruppi.add(new UserRoleBean("DF", "Delegato alla firma"));
			if (request.isUserInRole("SicuraWeb_VI"))
				gruppi.add(new UserRoleBean("VI", "Utente visualizzatore"));

		}
		uib.setGruppi(gruppi);
		return uib;		
	}
	
	@RequestMapping(value="/authentication_groups",method=RequestMethod.POST)
	@ResponseBody
	public List<UserRoleBean> getAuthenticationModes(@RequestBody LoginUserBean user, HttpServletRequest request){
			//RequestBody String username, @RequestBody String password,@RequestBody String userProfile) {
		setRequest(request);
 		List<UserRoleBean> res = new ArrayList<UserRoleBean>();
 		if(request.getRemoteUser()==null) {
			res.add(new UserRoleBean("TR","Tesoriere responsabile"));
			res.add(new UserRoleBean("AS","Amministratore di sistema"));
			res.add(new UserRoleBean("GI","Gestore informatico"));
			res.add(new UserRoleBean("DF", "Delegato alla firma"));
		} else {
			//res = userDAO.getRoles(user.getUsername(), user.getPassword());
		}
		
		return res;
	}
	
	@RequestMapping(value="/validSession",method=RequestMethod.GET)
	@ResponseBody
	public ResponseEntity<Boolean> isValidSession(HttpServletRequest request) {
		setRequest(request);

		if(getUserData()==null)
			return new ResponseEntity<Boolean>(false,HttpStatus.OK);
		else
			return new ResponseEntity<Boolean>(true, HttpStatus.OK);
	}

	
	@RequestMapping(value="/appvariables",method=RequestMethod.GET)
	@ResponseBody
	public ResponseEntity<Object> getAppvariables(HttpServletRequest request) {
		setRequest(request);
		AppVariables appVariables = (AppVariables) getSessionAttribute("appVariables");

		if(getUserData()==null)
			return new ResponseEntity<Object>(HttpStatus.UNAUTHORIZED);
		else
			return new ResponseEntity<Object>(appVariables, HttpStatus.OK);
	}
	
	@RequestMapping(value="/login", method=RequestMethod.POST)
	@ResponseBody
	public ResponseEntity<LoginUserBean> login(@RequestBody LoginUserBean beanUtente, HttpServletRequest request)  {
		
		String originalUserName = "";

		
		if (beanUtente.getUserProfile().equals("TR") && !request.isUserInRole("SicuraWeb_TR"))
			return new ResponseEntity<LoginUserBean>(HttpStatus.UNAUTHORIZED);
		if (beanUtente.getUserProfile().equals("AS") && !request.isUserInRole("SicuraWeb_AS"))
			return new ResponseEntity<LoginUserBean>(HttpStatus.UNAUTHORIZED);
		if (beanUtente.getUserProfile().equals("GI") && !request.isUserInRole("SicuraWeb_GI"))
			return new ResponseEntity<LoginUserBean>(HttpStatus.UNAUTHORIZED);
		if (beanUtente.getUserProfile().equals("DF") && !request.isUserInRole("SicuraWeb_DF"))
			return new ResponseEntity<LoginUserBean>(HttpStatus.UNAUTHORIZED);
		if (beanUtente.getUserProfile().equals("VI") && !request.isUserInRole("SicuraWeb_VI"))
			return new ResponseEntity<LoginUserBean>(HttpStatus.UNAUTHORIZED);
	
		
		ResponseEntity<LoginUserBean> res;
		
		UserData userData = new UserData();
		AppVariables appVariables = new AppVariables();
			
		boolean tx = userDAO.startTransaction();
		
		try {
			setRequest(request);
			boolean loginSuccessful = false;
			if (isFakeLogin(request)) {
				loginSuccessful = true;
			
			} else {
				// Forza l'utente
				if (request.getRemoteUser()!=null)
					beanUtente.setUsername(request.getRemoteUser());
				
				loginSuccessful = true;
			}
			String salt = getSaltString(null);
			
			Map<String, Object> slu = null;
			
			try {
	
				beanUtente.setUsername(beanUtente.getUsername().toUpperCase());
				originalUserName = beanUtente.getUsername();				
				
				Logger.getRootLogger().debug(String.format("Login: %s salf:%s auth.mode %s userprofile: %s",beanUtente.getUsername(),salt,appVariables.getAuthenticationMode(), beanUtente.getUserProfile()));
				CallableStatement cs = userDAO.getSecurityLogUser(beanUtente.getUsername().toUpperCase(), salt /*user.getPassword()*/, appVariables.getAuthenticationMode(), beanUtente.getUserProfile());
				
				ResultSet rs = cs.getResultSet();
				if (rs.next()) {
					if (rs.getString("Mode").equals("ERR"))
						loginSuccessful = false;
				}
					
				
				if (loginSuccessful && cs.getMoreResults()) {
					Utenti user = userDAO.getByUsername(beanUtente.getUsername(),beanUtente.getUserProfile()); // 
					
					if (user!=null) {
					
						
						beanUtente.setUserDescription(user.getDenominazione());
						userData.setUserId(user.getId());
						userData.setLastname(user.getDenominazione());
						userData.setCompanyCode(user.getCodiceSocietà());
						userData.setLogin(user.getUserId());
						userData.setOtherCode(beanUtente.getUserProfile());
						
						rs = cs.getResultSet();
						if (rs.next()) {
						
							//slub = (Map<String, Object>) ((ArrayList)slu.get("#result-set-2")).get(0);
							
							userData.setGuid((String) rs.getString("Guid"));
							appVariables.setGuid((String) rs.getString("Guid"));
							appVariables.setUserId((String) rs.getString("UserID"));
							appVariables.setDenominazioneUtente(rs.getString("Denominazione"));
							appVariables.setCodiceFiscaleUtente((String) rs.getString("CodiceFiscale"));
							appVariables.setProfiloLocale((String) rs.getString("ProfiloLocale"));
							appVariables.setFunzioneOrdinante((String) rs.getString("FunzioneOrdinante"));
							
							appVariables.setCodiceSocieta((String) rs.getString("CodiceSocietà"));
							appVariables.setCodiceFunzione((String) rs.getString("CodiceFunzione"));
							appVariables.setUserIDResponsabile1((String) rs.getString("UserIDResponsabile1"));
							appVariables.setUserIDResponsabile2((String) rs.getString("UserIDResponsabile2"));
							appVariables.setEmailResponsabile((String) rs.getString("EMailResponsabile"));
							appVariables.setImportoLimiteFirma((Double) rs.getDouble("ImportoLimiteFirma"));
							
							appVariables.setAbilitaBonifici(((Boolean) rs.getBoolean("AbilitazioneBonifici")));
							appVariables.setAbilitaBonificiEsteri(((Boolean) rs.getBoolean("AbilitazioneBonificiEsteri")));
							appVariables.setAbilitaAEA(((Boolean) rs.getBoolean("AbilitazioneAEA")));
							appVariables.setAbilitaAEA_Iban(((Boolean) rs.getBoolean("AbilitazioneAEA_Iban")));
							appVariables.setAbilitaRID(((Boolean) rs.getBoolean("AbilitazioneRID")));
							appVariables.setAbilitaVisualizzazioneGlobaleDisposizioni(((Boolean) rs.getBoolean("VisualizzazioneGlobaleDisposizioni")));
							appVariables.setAbilitaAccessoAnagrafica(((Boolean) rs.getBoolean("AbilitaAccessoAnagrafica")));
							appVariables.setAbilitaApprovazioneMassiva(((Boolean) rs.getBoolean("AbilitaApprovazioneMassiva")));
							appVariables.setAbilitaForzaturaSospeso(((Boolean) rs.getBoolean("AbilitaForzaturaSospeso")));
							appVariables.setBloccoModificaDisposizioni(((Boolean) rs.getBoolean("BloccoModificaDisposizioni")));
							if (rs.getTimestamp("DecorrenzaPassword")!=null)
								appVariables.setDecorrenzaPassword(new DateTime(((java.sql.Timestamp)rs.getTimestamp("DecorrenzaPassword")).getTime()));
						}
								
						if (cs.getMoreResults()) {
							rs = cs.getResultSet();
							if (rs.next()) {
								appVariables.setAbilitaCausale(((Boolean) rs.getBoolean("AbilitaCausali")));
								appVariables.setGestioneDatiContabili(((Boolean) rs.getBoolean("GestioneDatiContabili")));
								appVariables.setApprovazioneAutomatica(((Boolean) rs.getBoolean("ApprovazioneAutomatica")));
								
								appVariables.setAbilitaGiroconti(((Boolean) rs.getBoolean("AbilitaGiroconti")));
								appVariables.setAbilitaCircuitoCassa(((Boolean) rs.getBoolean("AbilitaCircuitoCassa")));
								appVariables.setAbilitaCircuitoPoste(((Boolean) rs.getBoolean("AbilitaCircuitoPoste")));
							}
						}
						
						if (cs.getMoreResults()) {
							rs = cs.getResultSet();
							if (rs.next()) {
								appVariables.setIdOrdinante(((Integer) rs.getInt("IDOrdinante")));
								appVariables.setDenominazioneOrdinante((String) rs.getString("Ordinante"));
								appVariables.setDelegheBancoPostaSuCircuitoBancari(((Boolean) rs.getBoolean("FlagAggiornaDistintadaArchivio")));
							}
						}
					} else {
						Logger.getRootLogger().debug("User è null");
						setUserData(null);
						res = new ResponseEntity<LoginUserBean>(HttpStatus.NOT_FOUND);
						beanUtente = null;
					}
					
				} else  {
					Logger.getRootLogger().debug("Chiamata a getMoreResult() fallita");
					setUserData(null);
					res = new ResponseEntity<LoginUserBean>(HttpStatus.NOT_FOUND);
					beanUtente = null;
				}
				if (tx) {
					userDAO.commit();
					tx = false;
				}
				
				} catch (IllegalArgumentException e) {
					// TODO Auto-generated catch block
					Logger.getRootLogger().error("Login " + originalUserName + ": " + e.getMessage());
					e.printStackTrace();
					beanUtente = null;
				} catch (SecurityException e) {
					Logger.getRootLogger().error("Login " + originalUserName + ": " + e.getMessage());					
					e.printStackTrace();
					beanUtente = null;
				} catch (SQLException e) {
					Logger.getRootLogger().error("Login " + originalUserName + ": " + e.getMessage());
					e.printStackTrace();
					beanUtente = null;
				}
			
			}finally {
				if (tx)
					userDAO.rollback();
			}
		
			setUserData(userData);

			setSessionAttribute("appVariables", appVariables);

			if (beanUtente!=null) {
				res = new ResponseEntity<LoginUserBean>(beanUtente, HttpStatus.OK);
				Logger.getRootLogger().info("Login effettuato correttamente per utente: " + beanUtente.getUsername() +  " con profilo " + beanUtente.getUserProfile());
			} else {
				res = new ResponseEntity<LoginUserBean>(HttpStatus.NOT_FOUND);
				Logger.getRootLogger().info("Login fallito per utente: " + originalUserName);
			}
			
		return res;
	}
	
	private String getSaltString(Utenti user) {
		char[] chars = "abcdefghijklmnopqrstuvwxyz".toCharArray();
		StringBuilder sb = new StringBuilder();
		Random random = new Random();
		for (int i = 0; i < 10; i++) {
		    char c = chars[random.nextInt(chars.length)];
		    sb.append(c);
		}
		String output = sb.toString();
		return output;
	}

	@RequestMapping(value="/logout", method=RequestMethod.GET)
	@ResponseBody
	public ResponseEntity<LoginUserBean> logout(HttpServletRequest request) {
		setRequest(request);
		setUserData(null);
		
		return new ResponseEntity<LoginUserBean>(HttpStatus.OK);
	
	}
	
	private boolean isFakeLogin(HttpServletRequest request) {
		Properties prop = new Properties();
		try {
				if (request.getSession().getServletContext().getResourceAsStream("/WEB-INF/properties/app.properties")!=null) {
		    //load a properties file from class path, inside static method
				prop.load(request.getSession().getServletContext().getResourceAsStream("/WEB-INF/properties/app.properties"));

				//get the property value and print it out
				if (prop.containsKey("fakeLogin"))
					return prop.getProperty("fakeLogin","0").equals("1"); 
			}
		} 
		catch (IOException ex) {
		    ex.printStackTrace();
		}
		
	    return false;
	
	}
	
	@RequestMapping("/count")
	@ResponseBody
	private ResponseEntity<Integer> count(HttpServletRequest request, @RequestParam(value="filter", required=false) String filter) {
		try {
			setRequest(request);
	
			if(getUserData()==null)
				return new ResponseEntity<Integer>(HttpStatus.UNAUTHORIZED);
			else {
				AppVariables appVariables = (AppVariables) getSessionAttribute("appVariables");
				if (!"AS".equals(appVariables.getProfiloLocale()))
						return new ResponseEntity<Integer>(HttpStatus.UNAUTHORIZED);
				return new ResponseEntity<Integer>(userDAO.count(filter), HttpStatus.OK);
			}
		} catch(Exception ex) {
			ex.printStackTrace();
			Logger.getRootLogger().error(ex);
			return new ResponseEntity<Integer>(0, HttpStatus.INTERNAL_SERVER_ERROR);
		}		
	}

	@RequestMapping("new")
	@ResponseBody
	private ResponseEntity<Object> newInstance(HttpServletRequest request) {
		try {
			setRequest(request);
	
			if(getUserData()==null)
				return new ResponseEntity<Object>(HttpStatus.UNAUTHORIZED);
			else
				return new ResponseEntity<Object>(userDAO.newInstance(), HttpStatus.OK);
		} catch(Exception ex) {
			ex.printStackTrace();
			Logger.getRootLogger().error(ex);
			return new ResponseEntity<>(false, HttpStatus.INTERNAL_SERVER_ERROR);
		}		
	}

	
	@RequestMapping("/list/{start:[\\d]+}-{length:[\\d]+}")
	@ResponseBody
	private ResponseEntity<Object> list(
			@PathVariable("start") int startFrom, 
			@PathVariable("length") int length,
			HttpServletRequest request,
			@RequestParam(value="filter", required=false) String filter,
			@RequestParam(value="orderField", required=false) String orderField) {
		try {
			setRequest(request);
			if(getUserData()==null)
				return new ResponseEntity<Object>(HttpStatus.UNAUTHORIZED);
			else {
				AppVariables appVariables = (AppVariables) getSessionAttribute("appVariables");
				if (!"AS".equals(appVariables.getProfiloLocale()))
						return new ResponseEntity<Object>(HttpStatus.UNAUTHORIZED);
				List<Utenti> utenti = userDAO.list(startFrom, length, filter, orderField);
				if (utenti==null)
					return new ResponseEntity<Object>(HttpStatus.INTERNAL_SERVER_ERROR);
				else
					return new ResponseEntity<Object>(utenti, HttpStatus.OK);
			}
		} catch(Exception ex) {
			ex.printStackTrace();
			Logger.getRootLogger().error(ex);
			return new ResponseEntity<>(false, HttpStatus.INTERNAL_SERVER_ERROR);
		}		
	}
	

	@RequestMapping(value="", method=RequestMethod.POST)
	@ResponseBody
	private ResponseEntity<Object> save(@RequestBody Utenti utente, HttpServletRequest request){
		try {
			setRequest(request);
	
			if(getUserData()==null)
				return new ResponseEntity<Object>(HttpStatus.UNAUTHORIZED);
			else {
				AppVariables appVariables = (AppVariables) getSessionAttribute("appVariables");
				if (!"AS".equals(appVariables.getProfiloLocale()))
						return new ResponseEntity<Object>(HttpStatus.UNAUTHORIZED);
				try {
					return new ResponseEntity<Object>(userDAO.saveOrUpdate(utente), HttpStatus.OK);
				} catch (Exception ex) {
					return new ResponseEntity<Object>(ex.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);
				}
			}
		} catch(Exception ex) {
			ex.printStackTrace();
			Logger.getRootLogger().error(ex);
			return new ResponseEntity<>(false, HttpStatus.INTERNAL_SERVER_ERROR);
		}		
	}

	@RequestMapping(value="/delete/{id}", method=RequestMethod.DELETE)
	@ResponseBody
	private ResponseEntity<Integer> delete(HttpServletRequest request, @PathVariable("id") Integer id) {
		try {
			setRequest(request);
	
			if(getUserData()==null)
				return new ResponseEntity<Integer>(HttpStatus.UNAUTHORIZED);
			else {
				AppVariables appVariables = (AppVariables) getSessionAttribute("appVariables");
				if (!"AS".equals(appVariables.getProfiloLocale()))
						return new ResponseEntity<Integer>(HttpStatus.UNAUTHORIZED);
	
				userDAO.eliminaUtente(id);
				return new ResponseEntity<Integer>(HttpStatus.OK);
			}
		} catch(Exception ex) {
			ex.printStackTrace();
			Logger.getRootLogger().error(ex);
			return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
		}		
	}
	
}
