package com.agilex.healthcare.schedulingmanager.resources;


import com.agilex.healthcare.mobilehealthplatform.domain.PatientIdentifier;
import com.agilex.healthcare.schedulingmanager.datalayer.SchedulingDataLayer;
import agilex.commons.pagination.PaginationDataLayer;
import com.agilex.healthcare.schedulingmanager.datalayer.SchedulingDataLayer;
import com.agilex.healthcare.schedulingmanager.dataservice.WaitListDataService;
import com.agilex.healthcare.schedulingmanager.domain.WaitListEntries;
import com.agilex.healthcare.schedulingmanager.domain.WaitListEntry;
import com.agilex.healthcare.schedulingmanager.domain.WaitListEntryDetail;
import com.agilex.healthcare.schedulingmanager.linkbuilder.WaitListLinkBuilder;
import com.agilex.healthcare.schedulingmanager.utils.ListType;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.ws.rs.*;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.UriInfo;
import java.util.HashMap;
import java.util.StringTokenizer;

@Deprecated
@Path("/scheduling-service/site/{facility-id}/waitlist")
@Component
@Scope("request")
public class WaitListResource {

    @Resource(name = "schedulingDataLayer")
    SchedulingDataLayer schedulingDataLayer;

    @Resource(name = "paginationDataLayer")
    PaginationDataLayer       paginationDataLayer;

    @Resource
    WaitListDataService       waitListDataService;

    /**
     * This resource returns list of all three Wait Lists (EWL, NEAR and Recall) for a given patient.
     *
     * This resource uses the following MDWS services:
     *
     *      LVSchedulingSvc/getEwlByPatient
     *      LVSchedulingSvc/getNearListByPatient
     *      LVSchedulingSvc/getRecallListByPatient
     *
     * @param assigningAuthority The assigning authority for this patient.
     *
     * @param patientId The unique identifier for this patient.
     *
     * @param facilityCode This is the facility code associated with the list data.  This parameter
     *                     is passed to the application in the URL.
     *
     * @param uriInfo This parameter contains information about the URI and is provided by the system.
     *
     * @param headers This parameter contains the http headers and is provided by the system.
     *
     * @return A WaitListEntries object.
     */
    @GET
    @Path("/patient/{assigning-authority}/{patient-id}")
    @Produces({ "application/xml", "application/json" })
    public WaitListEntries fetchPatientWaitList(@PathParam("assigning-authority") String assigningAuthority,
                                                @PathParam("patient-id") String patientId,
                                                @PathParam("facility-id") String facilityCode,
                                                @Context UriInfo uriInfo,
                                                @Context HttpHeaders headers) {
        PatientIdentifier     patientIdentifier = new PatientIdentifier(assigningAuthority, patientId);
        WaitListEntries       waitListEntries = schedulingDataLayer.getPatientWaitList(patientIdentifier, facilityCode);
//        WaitListLinkBuilder linkBuilder = new WaitListLinkBuilder(uriInfo.getBaseUri());
//        waitListEntries = linkBuilder.fillLinks(waitListEntries, uriInfo.getRequestUri(), facilityCode);
        return waitListEntries;
    }

    /**
     *
     * This call is currently unimplemented.
     *
     * This resource returns detailed information related to specific type of Wait List (e.g. EWL, Near or Recall).
     *
     * This resource uses the following MDWS services:
     *
     *      XXXXXXXX/YYYYYYYYY
     *
     * @param waitListId The unique id of the wait list.
     *
     * @param facilityCode This is the facility code associated with the list data.  This parameter
     *                     is passed to the application in the URL.
     *
     * @param waitListType This input parameter identifies the type of list the client is requesting.
     *                     Valid values are ewl, near and recall.  This parameter is passed to the
     *                     application in the URL.
     *
     * @param uriInfo This parameter contains information about the URI and is provided by the system.
     *
     * @param headers This parameter contains the http headers and is provided by the system.
     *
     * @return A WaitListEntryDetail object.
     */
    @GET
    @Path("/{waitlist-type}/id/{waitlist-id}/detail")
    @Produces({ "application/xml", "application/json" })
    public WaitListEntryDetail fetchElectronicWaitListDetail(@PathParam("waitlist-id") String waitListId,
                                                             @PathParam("facility-id") String facilityCode,
                                                             @PathParam("waitlist-type") String waitListType,
                                                             @Context UriInfo uriInfo,
                                                             @Context HttpHeaders headers){
        WaitListEntryDetail       waitListEntryDetail = new WaitListEntryDetail();
        if(waitListType != null && waitListType.equalsIgnoreCase("ewl")){
            WaitListLinkBuilder       linkBuilder = new WaitListLinkBuilder(uriInfo.getBaseUri());
            waitListEntryDetail = schedulingDataLayer.getWaitListEntryDetail(waitListId, facilityCode);
            waitListEntryDetail = linkBuilder.fillLinks(waitListEntryDetail,uriInfo.getRequestUri());
        }
        return waitListEntryDetail;
    }

    /**
     *
     * This call is currently unimplemented.
     *
     * This resource returns basic information related to specific type of Wait List (e.g. EWL, Near or Recall).
     *
     * @param waitListId The unique id of the wait list.
     *
     * This resource uses the following MDWS services:
     *
     *      XXXXXXXX/YYYYYYYYY
     *
     * @param facilityCode This is the facility code associated with the list data.  This parameter
     *                     is passed to the application in the URL.
     *
     * @param waitListType This input parameter identifies the type of list the client is requesting.
     *                     Valid values are ewl, near and recall.  This parameter is passed to the
     *                     application in the URL.
     *
     * @param uriInfo This parameter contains information about the URI and is provided by the system.
     *
     * @param headers This parameter contains the http headers and is provided by the system.
     *
     * @return A WaitListEntry object.
     */
    @GET
    @Path("/{waitlist-type}/id/{waitlist-id}")
    @Produces({ "application/xml", "application/json" })
    public WaitListEntry fetchElectronicWaitListEntry(@PathParam("waitlist-id") String waitListId,
                                                      @PathParam("facility-id") String facilityCode,
                                                      @PathParam("waitlist-type") String waitListType,
                                                      @Context UriInfo uriInfo, @Context HttpHeaders headers){
        WaitListEntry     waitListEntry = new WaitListEntry();
        if(waitListType != null && waitListType.equalsIgnoreCase("ewl")){
            waitListEntry = schedulingDataLayer.getWaitListEntry(waitListId, facilityCode);
            WaitListLinkBuilder       linkBuilder = new WaitListLinkBuilder(uriInfo.getBaseUri());
            waitListEntry = linkBuilder.fillLinks(waitListEntry, uriInfo.getRequestUri(), facilityCode);
        }
        return waitListEntry;
    }

    /**
     * This resource returns a list of all EWL, NEAR or Recall records for a given facility.
     * This service uses the pagination framework to cache the data that it retrieves from
     * Vista, allowing the application to move the sorting, filtering and pagination of the
     * list data from the mobile device to the backend REST server.
     *
     * This resource uses the following MDWS services:
     *
     *      LVSchedulingSvc/getEwlByFacility
     *      LVSchedulingSvc/getNearListByFacility
     *      LVSchedulingSvc/getRecallListByFacility
     *
     * @param facilityCode This is the facility code associated with the list data.  This parameter
     *                     is passed to the application in the URL.
     *
     * @param waitListType This input parameter identifies the type of list the client is requesting.
     *                     Valid values are ewl, near and recall.  This parameter is passed to the
     *                     application in the URL.
     *
     * @param refresh This parameter is part of the pagination framework and is used by the client
     *                to request that the server refresh the cache by pulling list data from Vista.
     *                Note that this request is will be silently ignored if the list data in the cache
     *                is older than the system defined minimum amount of time that data should be kept
     *                in the cache before allowing it to be refreshed.  This limitation prevents a
     *                race condition from occurring that would effectively disable caching degrade
     *                overall system performance.  Valid values are "true" and "false", with "true"
     *                being the default.
     *
     * @param maxPerPageStr This parameter is part of the pagination framework and is used by the client
     *                      to define the maximum number of list records to return.  Valid values are any
     *                      integer value greater than 0.  The default value is 20.
     *
     * @param goToPageStr This parameter is part of the pagination framework and is used by the client to
     *                    define the logical "page" to return data for.  Valid values are any
     *                    integer value greater than 0.  The default value is 1.
     *
     * @param sortOnString This parameter is part of the pagination framework and is used by the client to
     *                     define the fields to sort on and if the sort direction should be ascending.  An
     *                     example of the string to use to sort on the fields lastName (ascending) and
     *                     firstName (ascending) would be the string "lastName,true;firstName,true".
     *
     * @param filter This parameter is part of the pagination framework and is used by the client to filter
     *               the list data before selecting the data to return.
     *
     * @param uriInfo This parameter contains information about the URI and is provided by the system.
     *
     * @param headers This parameter contains the http headers and is provided by the system.
     *
     * @return This call returns
     */
    @GET
    @Path("/{waitlist-type}")
    @Produces({ "application/xml", "application/json" })
    public WaitListEntries fetchElectronicWaitListForFacility(@PathParam("facility-id") String facilityCode,
                                                              @PathParam("waitlist-type") String waitListType,
                                                              @QueryParam("refresh") String refresh,
                                                              @QueryParam("max-per-page") String maxPerPageStr,
                                                              @QueryParam("go-to-page") String goToPageStr,
                                                              @QueryParam("sort-on") String sortOnString,
                                                              @QueryParam("filter") String filter,
                                                              @Context UriInfo uriInfo,
                                                              @Context HttpHeaders headers) {
        WaitListEntries             waitListEntries;
        int                         gotoPage;
        int                         maxPerPage;
        HashMap<String, Boolean>    sortFields = null;

        //
        // Set default values for null parameters.
        //
        if(refresh == null) {
            refresh = "true";
        }

        maxPerPage = paginationDataLayer.parseMaxPerPage(maxPerPageStr);

        gotoPage = paginationDataLayer.parseGoToPage(goToPageStr);

        sortFields = paginationDataLayer.parseSortDataMap(sortOnString);


        waitListEntries = waitListDataService.getListForFacility(schedulingDataLayer, Boolean.parseBoolean(refresh), facilityCode,
                                                       getWaitListType(waitListType),
                                                       sortFields, filter,
                                                       paginationDataLayer.getStartRecord(gotoPage, maxPerPage),
                                                       paginationDataLayer.getStopRecord(gotoPage, maxPerPage));

        //
        // Adjust go to page back to a non zero based number.
        //
        gotoPage += 1;

        waitListEntries.setRecordCount(paginationDataLayer.getRecordCount(waitListType, facilityCode, null, null, null));
        int  pgCount;
        if (maxPerPage > 0) {
            pgCount = (int)waitListEntries.getRecordCount()/maxPerPage;
            if((int)waitListEntries.getRecordCount() % maxPerPage != 0) {
                pgCount++;
            }
        } else {
            pgCount = 0;
        }
        waitListEntries.setPageCount(pgCount);
        if(gotoPage > waitListEntries.getPageCount()) {
            waitListEntries.setCurrentPage(waitListEntries.getPageCount());
        }
        else {
            waitListEntries.setCurrentPage(gotoPage);
        }
        waitListEntries.setStartRecord((maxPerPage * (gotoPage - 1)) + 1);
        waitListEntries.setStopRecord(maxPerPage * (gotoPage));
        if(waitListEntries.getStopRecord() > waitListEntries.getRecordCount()){
            waitListEntries.setStopRecord(waitListEntries.getRecordCount());
        }

        return waitListEntries;
    }

    private ListType getWaitListType(String waitListType) {

        if(waitListType.equalsIgnoreCase(ListType.EWL.getName())) {
            return ListType.EWL;
        }
        else if(waitListType.equalsIgnoreCase(ListType.RECALL.getName())) {
            return ListType.RECALL;
        }
        else {
            return ListType.NEAR;
        }
    }


}
