package com.fp.facade.ejb;

import java.lang.reflect.Method;
import java.sql.SQLException;
import java.util.List;

import javax.ejb.Stateless;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import javax.ejb.TransactionManagement;
import javax.ejb.TransactionManagementType;
import javax.persistence.EntityManager;

import net.sf.json.JSONObject;

import com.fp.bpm.EngineExecutor;
import com.fp.bpm.report.ReportProcessor;
import com.fp.common.exception.APPException;
import com.fp.common.exception.ExceptionHandler;
import com.fp.common.fin.MessageGenerator;
import com.fp.common.logger.APPLogger;
import com.fp.dto.Response;
import com.fp.dto.helper.FileHelper;
import com.fp.dto.json.Serializer;
import com.fp.dto.query.QueryRequest;
import com.fp.facade.ejb.helper.BeanHelper;
import com.fp.facadeclient.ejb.FacadeBeanRemote;
import com.fp.general.security.rules.CloseAllSessions;
import com.fp.persistence.commondb.PersistenceHelper;
import com.fp.persistence.commondb.PersistenceManager;

/**
 * Session Bean implementation class FacadeBean
 */
@Stateless(name = "facadebean")
@TransactionManagement(value = TransactionManagementType.BEAN)
public class FacadeBean extends BeanHelper implements FacadeBeanRemote {

    // @PersistenceContext(unitName="ejb")
    // EntityManager em;

    /**
     * Metodo que permite verificar que el servicio este activo.
     *
     * @param pData Datos con los que se procesa la transaccion.
     * @return Object
     * @throws Exception
     */
    @Override
    public Object ping(String pData) throws Exception {
        try {
            this.fillThreadFacade(this.getCompany(pData));
            EntityManager em = PersistenceManager.getInstance().createEntityManagerLocal();
            PersistenceHelper.setEntityManager(em);
            Response res = new Response(Response.RESPONSE_OK, "OK" + pData);
            Serializer ser = new Serializer(res);
            return ser.toJSON();
        } catch (Exception e) {
            throw e;
        } finally {
            //PersistenceHelper.closeSession();
        }

    }

    /**
     * Metodo que se encarga de la ejecucion de una accion.
     *
     * @param pData Datos con los que se procesa la transaccion.
     * @param pFileItems Lista de archivos o imagenes a almacenar en la base.
     * @return Object
     * @throws Exception
     */
    @Override
    @TransactionAttribute(TransactionAttributeType.REQUIRED)
    public Object process(String pData, List<FileHelper> pFileItems) throws Throwable {
        this.fillThreadFacade(this.getCompany(pData));
        JSONObject response = new JSONObject();
        // Para obtener un EntityManager dinamico
        EntityManager em = PersistenceManager.getInstance().createEntityManagerLocal();
        PersistenceHelper.setEntityManager(em);
        try {
            BeanHelper.cleanThreadLocal();
            PersistenceHelper.beginTransaction();
            EngineExecutor ee = new EngineExecutor();
            String resp = ee.process(pData, pFileItems).toString();
            // em.flush();
            PersistenceHelper.commitTransaction();
            return resp;
        } catch (Throwable e) {
            APPLogger.getLogger().warn(e, e);
            PersistenceHelper.rollbackTransaction();
            try {
                this.fillError(e, response, pData);
            } catch (Throwable e1) {
                APPLogger.getLogger().warn(e1, e1);
            }
            return response.toString();
        } finally {
            PersistenceHelper.closeSession();
        }
    }

    private void fillError(Throwable e, Object pResponse, String pData) throws Exception {
        JSONObject response = (JSONObject) pResponse;
        APPLogger.getLogger().error("\nRequest:==>" + pData);
        ExceptionHandler eh = new ExceptionHandler(e, "es");
        String usrmsg = eh.getUserMessage();
        APPLogger.getLogger().error("User Message:==> " + usrmsg);
        response.put("message", usrmsg);
        response.put("messageCode", eh.getCode());
        response.put("isAplicationMessage", eh.isAppexception());
        response.put("trace", eh.getTechnicalMessage());
        if ((e instanceof APPException) || (e instanceof SQLException)) {
            response.put("stackTrace", eh.getTechnicalMessage());
        } else {
            response.put("stackTrace", eh.getStackTrace());
            APPLogger.getLogger().error("StackTrace:==>" + eh.getStackTrace());
        }
    }


    /**
     * Metodo que se encarga de expirar sessiones de usuario.
     *
     * @param host IP del servidor web
     */
    @Override
    public void expireSessions(String host) throws Exception {
        try {
            this.fillThreadFacade(this.getCompany(null));
            EntityManager em = PersistenceManager.getInstance().createEntityManagerLocal();
            PersistenceHelper.setEntityManager(em);
            PersistenceHelper.beginTransaction();
            CloseAllSessions.getInstance().expireSessions(host);
            PersistenceHelper.commitTransaction();
        } catch (Exception e) {
            PersistenceHelper.rollbackTransaction();
            APPLogger.getLogger().error("expireSessions==> " + e);
        } finally {
            PersistenceHelper.closeSession();
        }
    }

    /**
     * Metodo que se encarga de ejecutar y/o llenar tablas temporales para la ejeucion de reportes.
     *
     * @param pQueryRequest Datos de la consulta del reporte.
     * @throws Exception
     */
    @Override
    public Object reportProcessor(Object pQueryRequest) throws Exception {
        JSONObject response = new JSONObject();
        try {
            QueryRequest queryReq = (QueryRequest) pQueryRequest;
            this.fillThreadFacade(queryReq.getCompany());
            EntityManager em = PersistenceManager.getInstance().createEntityManagerLocal();
            PersistenceHelper.setEntityManager(em);
            PersistenceHelper.beginTransaction();
            Response res = new Response(Response.RESPONSE_OK, "OK");
            queryReq.setResponse(res);
            MessageGenerator mg = MessageGenerator.getInstance();
            queryReq.setJournalId(mg.generateId(queryReq.getUser()));
            ReportProcessor rp = new ReportProcessor();
            rp.process(queryReq);
            PersistenceHelper.commitTransaction();
            Serializer ser = new Serializer(res);
            return ser.toJSON();
        } catch (Exception e) {
            PersistenceHelper.rollbackTransaction();
            this.fillError(e, response, "");
        } finally {
            PersistenceHelper.closeSession();
        }
        return response.toString();

    }

}
