package com.agilex.healthcare.schedulingmanager.datalayer.userhistory;

import com.agilex.healthcare.mobilehealthplatform.domain.PatientData;
import com.agilex.healthcare.schedulingmanager.datalayer.PersistenceObject;
import com.agilex.healthcare.schedulingmanager.datalayer.SimpleEntityManager;
import com.agilex.healthcare.utility.XmlHelper;

import javax.persistence.EntityManager;
import java.util.Date;

public class UserHistoryEntityManager<T extends PersistenceObject> extends SimpleEntityManager<T> {
    private static final org.apache.commons.logging.Log logger = org.apache.commons.logging.LogFactory.getLog(UserHistoryEntityManager.class);

    private String table;
    private PatientData patientData;

    public UserHistoryEntityManager(EntityManager entityManager, String table, PatientData patientData) {
        super(entityManager);
        this.table = table;
        this.patientData = patientData;
    }

    public UserHistoryEntityManager(EntityManager entityManager, String table) {
        super(entityManager);
        this.table = table;
    }

    @Override
    public T save(T po) {
        T result = super.save(po);
        if (result != null) {
            save(createUserHistory(result.getId(), opType(po.getId() == null)), result);
        }

        return result;
    }

    private String opType(boolean hasId) {
        return hasId ? UserHistoryPo.INSERT_OP : UserHistoryPo.UPDATE_OP;
    }

    @Override
    public void delete(PatientData patientData, Class<T> returnType) {
        super.delete(patientData, returnType);

        recordUserDelete(patientData);
    }

    private void recordUserDelete(PatientData patientData) {
        this.patientData = patientData;

        save(createUserHistory(patientData.getUniqueId(), UserHistoryPo.DELETE_OP), null);
    }

    private UserHistoryPo createUserHistory(String id, String operation) {
         UserHistoryPo po = new UserHistoryPo();

        po.setRowId(id);
        po.setUserId(getUserID());
        po.setTableName(table);
        po.setOperation(operation);
        po.setActionDate(new Date());

        return po;
    }

    private String getUserID() {
        return patientData.getSurrogateId() != null ? patientData.getSurrogateId() : patientData.getPatientId();
    }

    public void save(UserHistoryPo userHistoryPo, T po) {
        serializeData(userHistoryPo, po);

        try {
            userHistoryPo = entityManager.merge(userHistoryPo);
        } catch (Exception e) {
            logException("Unable save user history for: ", e.getMessage(), userHistoryPo);
        }
    }

    private void serializeData(UserHistoryPo userHistoryPo, T po) {
        try {
            userHistoryPo.setData(XmlHelper.objectToXML(po));
        } catch (Exception e) {
            logException("Unable to serialize data for: ", e.getMessage(), userHistoryPo);
        }
    }

    private void logException(String beginning, String message, UserHistoryPo userHistoryPo) {
        logger.error(beginning + userHistoryPo.getOperation() + " " +
                userHistoryPo.getTableName() + " data with row id: " +userHistoryPo.getRowId() +
                ". " + message);
    }
}
