package com.agilex.healthcare.schedulingmanager.mdws.connection;


import java.io.Serializable;
import java.net.URL;
import java.util.Date;
import java.util.UUID;

import javax.xml.namespace.QName;
import javax.xml.ws.BindingProvider;

import com.agilex.healthcare.schedulingmanager.mdws.generatedwsdl.queryservice.QuerySvcSoap;
import org.apache.cxf.endpoint.Client;
import org.apache.cxf.frontend.ClientProxy;
import org.apache.cxf.transport.http.HTTPConduit;
import org.apache.cxf.transports.http.configuration.HTTPClientPolicy;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;

import com.agilex.healthcare.mobilehealthplatform.domain.MhpUser;
import com.agilex.healthcare.mobilehealthplatform.security.AppUser;
import com.agilex.healthcare.schedulingmanager.mdws.MdwsResponseException;
import com.agilex.healthcare.schedulingmanager.mdws.generatedwsdl.queryservice.QuerySvc;
import com.agilex.healthcare.schedulingmanager.mdws.generatedwsdl.queryservice.DataSourceArray;

public class QueryConnection implements Serializable {
	//private static final org.apache.commons.logging.Log logger = org.apache.commons.logging.LogFactory.getLog(SchedulingConnection.class);
    private static final long serialVersionUID = -978507159875320587L;

    private String id;
    private MdwsConfiguration configuration;
    private QuerySvcSoap port;
    private Date refreshedTimestamp;
    //private VistaSite site;

    public QueryConnection() {
        this.id = UUID.randomUUID().toString();
    }

    public QueryConnection(QuerySvcSoap port) {
        this.id = UUID.randomUUID().toString();
        this.port = port;
    }


    public QueryConnection(MdwsConfiguration configuration, String siteCode, boolean authenticateFlag) {
        this.id = UUID.randomUUID().toString();
        this.configuration = configuration;
        this.port = establishConnection(configuration, siteCode, authenticateFlag);
        this.refreshedTimestamp = new Date();
    }

    private QuerySvcSoap establishConnection(MdwsConfiguration configuration, String siteCode, boolean authenticated) {
        String baseUrl = "";

        MhpUser mhpUser = null;
		
		if (authenticated){
			mhpUser = getMhpUser();
			baseUrl = mhpUser.getMdwsInfo().getBaseUrl();
		}else{
			baseUrl = configuration.getEndPointBaseUrl();
		}
   		
        configuration.setEndPointBaseUrl(baseUrl);

   		String url = baseUrl + configuration.getEndPointUrl();

    	URL wsdlLocation = constructWsdlUrl(url);
        QuerySvc querySvc = null;
        try {
        	querySvc = new QuerySvc(wsdlLocation, new QName("http://mdws.domain/QuerySvc", "QuerySvc"));
        } catch (Throwable t) {
			throw new MdwsResponseException(MdwsResponseException.UserMessages.CONNECTION_ERROR, t.getMessage());
		}
        QuerySvcSoap port;
		try {
			port = querySvc.getQuerySvcSoap();
		} catch (Throwable t) {
            throw new MdwsResponseException(MdwsResponseException.UserMessages.CONNECTION_ERROR, t.getMessage());
        }

        ((BindingProvider)port).getRequestContext().put(BindingProvider.SESSION_MAINTAIN_PROPERTY, true);
        ((BindingProvider)port).getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, url);
        ((BindingProvider)port).getRequestContext().put("javax.xml.ws.client.connectionTimeout", configuration.getWsConnectTimeout());
        ((BindingProvider)port).getRequestContext().put("javax.xml.ws.client.receiveTimeout", configuration.getWsRequestTimeout());

//        if(authenticated) {
//            this.site = configuration.getVistaSite(siteCode);
//            validateVistaAccount(this.site, siteCode);
//        }

        if(authenticated) {
        		setSessionOnPort(port, mhpUser.getMdwsInfo().getSessionId());
        }
        else {
            DataSourceArray dsa = null;
            try {
                dsa = port.connect(siteCode);
            } catch (Throwable t) {
                throw new MdwsResponseException(MdwsResponseException.UserMessages.CONNECTION_ERROR, t.getMessage());
            }
            if (dsa.getFault() != null)
                throw new MdwsResponseException(MdwsResponseException.UserMessages.CONNECTION_ERROR, dsa.getFault());

//            if(authenticated) {
//                UserTO result = port.login(site.getAccessCode(), site.getVerifyCode(), "");
//                if (result.getFault() != null) {
//                    try {port.disconnect();} catch (Throwable t) { logger.info("Problem trying to dispose connection: " + t.getMessage());}
//                    throw new MdwsResponseException(MdwsResponseException.UserMessages.INVALID_ACCESS_VERIFY, result.getFault());
//                }
//            }
        }

        return port;
    }
    
	private  MhpUser getMhpUser(){
        SecurityContext ctx = SecurityContextHolder.getContext();

        AppUser appUser = (AppUser) ctx.getAuthentication().getPrincipal();
        MhpUser mhpUser = appUser.getMhpUser();
		mhpUser.setUserName(appUser.getUsername());

        return mhpUser;
	}
    
	private void setSessionOnPort(QuerySvcSoap port, String sessionId) {
		Client client = ClientProxy.getClient(port);

		HTTPClientPolicy policy = new HTTPClientPolicy();
		HTTPConduit httpConduit = (HTTPConduit)client.getConduit();
		
		policy.setCookie("ASP.NET_SessionId=" + sessionId);
		
		httpConduit.setClient(policy);
	}
    

    private URL constructWsdlUrl(String endPointUrl){
        String wsdlLocation = endPointUrl + "?WSDL";
        URL wsdlLocationURL = null;
        try {
            wsdlLocationURL = new URL(wsdlLocation);
        } catch (Exception e) {
        	throw new MdwsResponseException(MdwsResponseException.UserMessages.INVALID_WSDL, e.getMessage());
        }

        return wsdlLocationURL;
    }

    public Date getRefreshedTimestamp() {
        return refreshedTimestamp;
    }

    public void refreshTimestamp() {
        this.refreshedTimestamp = new Date();
    }

    public String getId() {
        return id;
    }

    public QuerySvcSoap getPort() {
        return port;
    }

    public MdwsConfiguration getConfiguration() {
        return this.configuration;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((id == null) ? 0 : id.hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        QueryConnection other = (QueryConnection) obj;
        if (id == null) {
            if (other.id != null)
                return false;
        } else if (!id.equals(other.id))
            return false;
        return true;
    }
}
