<cfcomponent displayname="EVV Status Manager" hint="Manages EVV status tracking and change detection" output="false">
	
	<cffunction name="init" displayname="Initialize Component" access="public" returntype="EVVStatusManager" hint="I initialize and return the EVVStatusManager object.">
		<cfreturn this>
	</cffunction>
	
	<!--- Function to check if data has changed after EVV transmission --->
	<cffunction name="checkForDataChanges" access="public" returntype="struct" output="false">
		<cfargument name="API_Type" required="yes" hint="clients, employee, or visits">
		<cfargument name="Record_ID" required="yes" hint="Patient_ID, Emp_ID, or Schedule_ID">
		<cfargument name="Agency_ID" required="yes" hint="Agency ID">
		
		<cfset var result = structNew()>
		<cfset result.hasChanges = false>
		<cfset result.changeDetails = "">
		<cfset result.lastEVVDate = "">
		
		<!--- Get the last EVV transmission date for successfully transmitted records --->
		<cfquery name="getLastEVV" datasource="#Application.DataSrc#">
			SELECT Date_Create, San_status
			FROM #Request.prefix_db_lookup#.EVV
			WHERE API_Type = <cfqueryparam value="#arguments.API_Type#" cfsqltype="cf_sql_varchar">
			AND Agency_ID = <cfqueryparam value="#arguments.Agency_ID#" cfsqltype="cf_sql_integer">
			AND status = 0
			AND (
				UPPER(San_status) LIKE '%SUCCESS%'
				OR UPPER(San_status) LIKE '%TRANSMITTED%'
				OR UPPER(San_status) LIKE '%TRANSACTION RECEIVED%'
			)
			<cfif arguments.API_Type EQ 'clients'>
				AND Patient_ID = <cfqueryparam value="#arguments.Record_ID#" cfsqltype="cf_sql_integer">
			<cfelseif arguments.API_Type EQ 'employee'>
				AND Emp_ID = <cfqueryparam value="#arguments.Record_ID#" cfsqltype="cf_sql_integer">
			<cfelseif arguments.API_Type EQ 'visits'>
				AND Schedule_ID = <cfqueryparam value="#arguments.Record_ID#" cfsqltype="cf_sql_integer">
			</cfif>
			ORDER BY EVV_ID DESC
			LIMIT 1
		</cfquery>
		
		<cfif getLastEVV.recordcount GT 0>
			<cfset result.lastEVVDate = getLastEVV.Date_Create>
			
			<!--- Check for changes based on API type --->
			<cfif arguments.API_Type EQ 'clients'>
				<cfset result = checkClientChanges(arguments.Record_ID, getLastEVV.Date_Create, result)>
			<cfelseif arguments.API_Type EQ 'employee'>
				<cfset result = checkEmployeeChanges(arguments.Record_ID, getLastEVV.Date_Create, result)>
			<cfelseif arguments.API_Type EQ 'visits'>
				<cfset result = checkVisitChanges(arguments.Record_ID, getLastEVV.Date_Create, result)>
			</cfif>
		</cfif>
		
		<cfreturn result>
	</cffunction>
	
	<!--- Check for client data changes --->
	<cffunction name="checkClientChanges" access="private" returntype="struct" output="false">
		<cfargument name="Patient_ID" required="yes">
		<cfargument name="lastEVVDate" required="yes">
		<cfargument name="result" required="yes">
		
		<cftry>
			<!--- Add 2 minute grace period to avoid false positives from automatic updates --->
			<cfset graceDateTime = DateAdd("n", 2, arguments.lastEVVDate)>
			
			<cfquery name="checkClientUpdates" datasource="#Application.DataSrc#">
				SELECT COUNT(*) as change_count
				FROM #Request.prefix_db_agency#.pPatients
				WHERE Patient_ID = <cfqueryparam value="#arguments.Patient_ID#" cfsqltype="cf_sql_integer">
				AND Record_Mod_Date IS NOT NULL
				AND Record_Mod_Date > <cfqueryparam value="#graceDateTime#" cfsqltype="cf_sql_timestamp">
			</cfquery>
			
			<cfif checkClientUpdates.change_count GT 0>
				<cfset arguments.result.hasChanges = true>
				<cfset arguments.result.changeDetails = "Client information has been modified since last EVV transmission.">
			</cfif>
			
			<cfcatch type="any">
				<!--- If Record_Mod_Date column doesn't exist or other error, silently fail --->
				<cfset arguments.result.hasChanges = false>
			</cfcatch>
		</cftry>
		
		<cfreturn arguments.result>
	</cffunction>
	
	<!--- Check for employee data changes --->
	<cffunction name="checkEmployeeChanges" access="private" returntype="struct" output="false">
		<cfargument name="Emp_ID" required="yes">
		<cfargument name="lastEVVDate" required="yes">
		<cfargument name="result" required="yes">
		
		<cftry>
			<!--- Add 2 minute grace period to avoid false positives from automatic updates --->
			<cfset graceDateTime = DateAdd("n", 2, arguments.lastEVVDate)>
			
			<cfquery name="checkEmpUpdates" datasource="#Application.DataSrc#">
				SELECT COUNT(*) as change_count
				FROM #Request.prefix_db_lookup#.pEmployee
				WHERE Emp_ID = <cfqueryparam value="#arguments.Emp_ID#" cfsqltype="cf_sql_integer">
				AND Record_Mod_Date IS NOT NULL
				AND Record_Mod_Date > <cfqueryparam value="#graceDateTime#" cfsqltype="cf_sql_timestamp">
			</cfquery>
			
			<cfif checkEmpUpdates.change_count GT 0>
				<cfset arguments.result.hasChanges = true>
				<cfset arguments.result.changeDetails = "Employee information has been modified since last EVV transmission.">
			</cfif>
			
			<cfcatch type="any">
				<!--- If Record_Mod_Date column doesn't exist or other error, silently fail --->
				<cfset arguments.result.hasChanges = false>
			</cfcatch>
		</cftry>
		
		<cfreturn arguments.result>
	</cffunction>
	
	<!--- Check for visit data changes --->
	<cffunction name="checkVisitChanges" access="private" returntype="struct" output="false">
		<cfargument name="Schedule_ID" required="yes">
		<cfargument name="lastEVVDate" required="yes">
		<cfargument name="result" required="yes">
		
		<cftry>
			<!--- Add 2 minute grace period to avoid false positives from automatic updates --->
			<cfset graceDateTime = DateAdd("n", 2, arguments.lastEVVDate)>
			
			<cfquery name="checkVisitUpdates" datasource="#Application.DataSrc#">
				SELECT COUNT(*) as change_count
				FROM #Request.prefix_db_agency#.pSchedules
				WHERE Schedule_ID = <cfqueryparam value="#arguments.Schedule_ID#" cfsqltype="cf_sql_integer">
				AND Date_Change IS NOT NULL
				AND Date_Change > <cfqueryparam value="#graceDateTime#" cfsqltype="cf_sql_timestamp">
			</cfquery>
			
			<cfif checkVisitUpdates.change_count GT 0>
				<cfset arguments.result.hasChanges = true>
				<cfset arguments.result.changeDetails = "Visit information has been modified since last EVV transmission.">
			</cfif>
			
			<cfcatch type="any">
				<!--- If Date_Change column doesn't exist or other error, silently fail --->
				<cfset arguments.result.hasChanges = false>
			</cfcatch>
		</cftry>
		
		<cfreturn arguments.result>
	</cffunction>
	
	<!--- Function to update EVV status when data changes --->
	<cffunction name="updateEVVStatusForChanges" access="public" returntype="boolean" output="false">
		<cfargument name="API_Type" required="yes" hint="clients, employee, or visits">
		<cfargument name="Record_ID" required="yes" hint="Patient_ID, Emp_ID, or Schedule_ID">
		<cfargument name="Agency_ID" required="yes" hint="Agency ID">
		
		<cfset var changeResult = checkForDataChanges(arguments.API_Type, arguments.Record_ID, arguments.Agency_ID)>
		
		<cfif changeResult.hasChanges>
			<!--- First, get the latest EVV_ID that was successfully transmitted --->
			<cfquery name="getLatestEVV" datasource="#Application.DataSrc#">
				SELECT EVV_ID, San_status
				FROM #Request.prefix_db_lookup#.EVV 
				WHERE API_Type = <cfqueryparam value="#arguments.API_Type#" cfsqltype="cf_sql_varchar">
				AND Agency_ID = <cfqueryparam value="#arguments.Agency_ID#" cfsqltype="cf_sql_integer">
				AND status = 0
				AND (
					UPPER(San_status) LIKE '%SUCCESS%'
					OR UPPER(San_status) LIKE '%TRANSMITTED%'
					OR UPPER(San_status) LIKE '%TRANSACTION RECEIVED%'
				)
				<cfif arguments.API_Type EQ 'clients'>
					AND Patient_ID = <cfqueryparam value="#arguments.Record_ID#" cfsqltype="cf_sql_integer">
				<cfelseif arguments.API_Type EQ 'employee'>
					AND Emp_ID = <cfqueryparam value="#arguments.Record_ID#" cfsqltype="cf_sql_integer">
				<cfelseif arguments.API_Type EQ 'visits'>
					AND Schedule_ID = <cfqueryparam value="#arguments.Record_ID#" cfsqltype="cf_sql_integer">
				</cfif>
				ORDER BY EVV_ID DESC
				LIMIT 1
			</cfquery>
			
			<!--- Then update the status --->
			<cfif getLatestEVV.recordcount GT 0>
				<cfquery name="updateEVVStatus" datasource="#Application.DataSrc#">
					UPDATE #Request.prefix_db_lookup#.EVV 
					SET San_status = 'Data Changed - Retransmission Required',
						Date_Update = NOW()
					WHERE EVV_ID = <cfqueryparam value="#getLatestEVV.EVV_ID#" cfsqltype="cf_sql_integer">
					AND (
						UPPER(San_status) LIKE '%SUCCESS%'
						OR UPPER(San_status) LIKE '%TRANSMITTED%'
						OR UPPER(San_status) LIKE '%TRANSACTION RECEIVED%'
					)
					AND (
						UPPER(San_status) NOT LIKE '%FAILED%'
						AND UPPER(San_status) NOT LIKE '%ERROR%'
						AND UPPER(San_status) NOT LIKE '%REJECTED%'
						AND UPPER(San_status) NOT LIKE '%DATA CHANGED%'
					)
				</cfquery>
				
				<cfreturn true>
			</cfif>
		</cfif>
		
		<cfreturn false>
	</cffunction>
	
	<!--- Function to get current EVV status with change detection --->
	<cffunction name="getEVVStatusWithChangeDetection" access="public" returntype="struct" output="false">
		<cfargument name="API_Type" required="yes" hint="clients, employee, or visits">
		<cfargument name="Record_ID" required="yes" hint="Patient_ID, Emp_ID, or Schedule_ID">
		<cfargument name="Agency_ID" required="yes" hint="Agency ID">
		
		<cfset var result = structNew()>
		<cfset result.EVV_Status = "Not Transmitted">
		<cfset result.ButtonsDisabled = false>
		<cfset result.HasChanges = false>
		
		<!--- Get current EVV status --->
		<cfquery name="getEVVStatus" datasource="#Application.DataSrc#">
			SELECT San_status, Date_Create
			FROM #Request.prefix_db_lookup#.EVV
			WHERE LOWER(TRIM(IFNULL(API_Type, ''))) = <cfqueryparam value="visits" cfsqltype="cf_sql_varchar">
			AND Agency_ID = <cfqueryparam value="#arguments.Agency_ID#" cfsqltype="cf_sql_integer">
			AND status = 0
			<cfif arguments.API_Type EQ 'clients'>
				AND Patient_ID = <cfqueryparam value="#arguments.Record_ID#" cfsqltype="cf_sql_integer">
			<cfelseif arguments.API_Type EQ 'employee'>
				AND Emp_ID = <cfqueryparam value="#arguments.Record_ID#" cfsqltype="cf_sql_integer">
			<cfelseif arguments.API_Type EQ 'visits'>
				AND Schedule_ID = <cfqueryparam value="#arguments.Record_ID#" cfsqltype="cf_sql_integer">
			</cfif>
			ORDER BY EVV_ID DESC
			LIMIT 1
		</cfquery>
		
		<cfif getEVVStatus.recordcount GT 0>
			<cfif FindNoCase('Transaction Received', getEVVStatus.San_status) GT 0>
				<cfset result.EVV_Status = "Transaction Received">
				<cfset result.ButtonsDisabled = true>  <!--- Disable both EVV and Status Check buttons --->
				
			<!--- Check for data changes after successful transmission
			<cfset var changeResult = checkForDataChanges(arguments.API_Type, arguments.Record_ID, arguments.Agency_ID)>
			<cfif changeResult.hasChanges>
				<!--- Data has been modified - reactivate buttons for retransmission --->
				<cfset result.EVV_Status = "Data Changed - Retransmission Required">
				<cfset result.ButtonsDisabled = false>
				<cfset result.HasChanges = true>
				
				<!--- Update the EVV status in database (fallback - triggers should handle this automatically) --->
				<!--- Note: If triggers are installed, this is redundant but provides safety --->
				<cfset updateEVVStatusForChanges(arguments.API_Type, arguments.Record_ID, arguments.Agency_ID)>
			</cfif> --->
			<!--- #10645: transmitted but status not checked yet --->
			<cfelseif getEVVStatus.San_status EQ 'Transmitted - Initial submission'
				OR getEVVStatus.San_status EQ 'Transmitted - Missed visit update'
				OR getEVVStatus.San_status EQ 'Transmitted - awaiting status check'
				OR FindNoCase('awaiting status', getEVVStatus.San_status) GT 0>
				<cfset result.EVV_Status = "Transmitted - awaiting status check">
				<cfset result.ButtonsDisabled = false>  <!--- Enable Status Check --->
			<!--- #10645: HHA transactionId status after Status Check --->
			<cfelseif getEVVStatus.San_status EQ 'Pending' OR getEVVStatus.San_status EQ 'PENDING'
				OR FindNoCase('Pending', getEVVStatus.San_status) GT 0 OR FindNoCase('Processing', getEVVStatus.San_status) GT 0>
				<cfset result.EVV_Status = "Pending">
				<cfset result.ButtonsDisabled = false>
			<cfelseif arguments.API_Type EQ 'visits' AND (getEVVStatus.San_status EQ 'Success' OR getEVVStatus.San_status EQ 'SUCCESS')>
				<!--- HHA Exchange success status --->
				<cfset result.EVV_Status = "Success">
				<cfset result.ButtonsDisabled = true>
			<cfelseif FindNoCase('Complete', getEVVStatus.San_status) GT 0 OR FindNoCase('Processed', getEVVStatus.San_status) GT 0 OR FindNoCase('Accepted', getEVVStatus.San_status) GT 0>
				<cfset result.EVV_Status = "Transaction Received">
				<cfset result.ButtonsDisabled = true>
			<cfelseif getEVVStatus.San_status EQ 'Failed' OR getEVVStatus.San_status EQ 'FAILED' OR FindNoCase('Failed', getEVVStatus.San_status) GT 0>
				<cfset result.EVV_Status = "Failed">
				<cfset result.ButtonsDisabled = false>
			<cfelseif getEVVStatus.San_status EQ 'Transmitted'>
				<cfset result.EVV_Status = "Transmitted">
				<cfset result.ButtonsDisabled = true>  <!--- Disable Send EVV button to prevent duplicate transmission --->
			<cfelseif FindNoCase('SUCCESS', getEVVStatus.San_status) GT 0>
				<cfset result.EVV_Status = "Success">
				<cfset result.ButtonsDisabled = true>
			<cfelseif FindNoCase('Data Changed', getEVVStatus.San_status) GT 0>
				<cfset result.EVV_Status = "Data Changed - Retransmission Required">
				<cfset result.HasChanges = true>
				<cfset result.ButtonsDisabled = false>  <!--- Enable buttons for re-transmission --->
			<cfelseif len(trim(getEVVStatus.San_status)) GT 0>
				<cfset result.EVV_Status = "Error">
				<cfset result.ButtonsDisabled = false>  <!--- Enable buttons for error retry --->
			</cfif>
		</cfif>
		
		<cfreturn result>
	</cffunction>

	<!--- #10645 Manual report statuses:
		Not Transmitted | Transmitted - awaiting status check | Pending | Failed | Success --->
	<cffunction name="resolveVisitEVVStatusDisplay" access="public" returntype="string" output="false">
		<cfargument name="dbStatus" type="string" required="true">
		<cfargument name="activeJob" type="struct" required="true">

		<cfset var display = trim(arguments.dbStatus)>
		<cfset var jobStatus = "">

		<cfif findNoCase("Transaction Received", display) GT 0 OR compareNoCase(display, "Success") EQ 0>
			<cfreturn (compareNoCase(display, "Success") EQ 0) ? "Success" : "Transaction Received">
		</cfif>
		<cfif compareNoCase(display, "Failed") EQ 0 OR compareNoCase(display, "FAILED") EQ 0>
			<cfreturn "Failed">
		</cfif>
		<!--- Exact HHA Pending after Status Check — do not collapse into awaiting --->
		<cfif compareNoCase(display, "Pending") EQ 0 OR compareNoCase(display, "PENDING") EQ 0>
			<cfreturn "Pending">
		</cfif>
		<!--- Sent, but Status Check not run yet (or still waiting for first poll) --->
		<cfif display EQ "Transmitted - Initial submission"
			OR display EQ "Transmitted - Missed visit update"
			OR display EQ "Transmitted - awaiting status check"
			OR findNoCase("awaiting status", display) GT 0>
			<cfset display = "Transmitted - awaiting status check">
		</cfif>

		<cfif structKeyExists(arguments.activeJob, "evvStatus") AND len(trim(arguments.activeJob.evvStatus))>
			<cfset jobStatus = trim(arguments.activeJob.evvStatus)>
			<cfif findNoCase("Transaction Received", jobStatus) GT 0>
				<cfreturn "Transaction Received">
			</cfif>
			<cfif compareNoCase(jobStatus, "Success") EQ 0>
				<cfreturn "Success">
			</cfif>
			<cfif compareNoCase(jobStatus, "Failed") EQ 0>
				<cfreturn "Failed">
			</cfif>
			<cfif compareNoCase(jobStatus, "Pending") EQ 0>
				<cfreturn "Pending">
			</cfif>
			<cfif findNoCase("awaiting status", jobStatus) GT 0
				OR jobStatus EQ "Transmitted - Initial submission"
				OR jobStatus EQ "Transmitted - Missed visit update">
				<cfset jobStatus = "Transmitted - awaiting status check">
			</cfif>
			<cfif jobStatus NEQ "Not Transmitted">
				<cfset display = jobStatus>
			</cfif>
		</cfif>
		<!--- Active automation job before first HHA status result — still awaiting check, not Pending --->
		<cfif structKeyExists(arguments.activeJob, "hasActiveJob") AND arguments.activeJob.hasActiveJob
			AND structKeyExists(arguments.activeJob, "jobStatus")
			AND listFindNoCase("pending_transmit,waiting_status,polling_status", arguments.activeJob.jobStatus) GT 0
			AND (
				display EQ "Not Transmitted"
				OR display EQ "Transmitted - Initial submission"
				OR display EQ "Transmitted - Missed visit update"
				OR display EQ "Transmitted - awaiting status check"
				OR findNoCase("awaiting", display) GT 0
			)>
			<cfset display = "Transmitted - awaiting status check">
		</cfif>

		<cfreturn display>
	</cffunction>

	<cffunction name="getEVVAgenciesList" access="public" returntype="string" output="false">
		<cfif structKeyExists(session, "EVVagencies") AND len(trim(session.EVVagencies)) GT 0>
			<cfreturn trim(session.EVVagencies)>
		</cfif>
		<cfif structKeyExists(application, "EVVagencies") AND len(trim(application.EVVagencies)) GT 0>
			<cfreturn trim(application.EVVagencies)>
		</cfif>
		<cfreturn "">
	</cffunction>

	<cffunction name="agencyUsesEVVAutomation" access="public" returntype="boolean" output="false">
		<cfargument name="agencyID" type="numeric" required="true">
		<cfset var evvAgencies = getEVVAgenciesList()>
		<cfif NOT len(evvAgencies)>
			<cfreturn false>
		</cfif>
		<cfreturn listFind(evvAgencies, arguments.agencyID) GT 0>
	</cffunction>

	<!--- #10527: auto_send (auto-send) vs manual_trans (review first) --->
	<cffunction name="getAgencyEVVTransmissionMode" access="public" returntype="string" output="false">
		<cfargument name="agencyID" type="numeric" required="true">
		<cfset var mode = "auto_send">
		<cfset var qAgency = "">
		<cfset var raw = "">
		<cfif NOT len(trim(Request.prefix_db_lookup))>
			<cfset Request.prefix_db_lookup = "hhapowerpath">
		</cfif>
		<cftry>
			<cfquery name="qAgency" datasource="#Application.DataSrc#">
				SELECT EVV_Transmission
				FROM #Request.prefix_db_lookup#.Agency
				WHERE Agency_ID = <cfqueryparam value="#arguments.agencyID#" cfsqltype="cf_sql_integer">
				LIMIT 1
			</cfquery>
			<cfif qAgency.recordCount GT 0 AND len(trim(qAgency.EVV_Transmission))>
				<cfset raw = lCase(trim(qAgency.EVV_Transmission))>
				<cfif raw EQ "manual_trans" OR find("review", raw) GT 0 OR raw EQ "manual">
					<cfset mode = "manual_trans">
				<cfelse>
					<cfset mode = "auto_send">
				</cfif>
			</cfif>
			<cfcatch type="any">
				<cfset mode = "auto_send">
			</cfcatch>
		</cftry>
		<cfreturn mode>
	</cffunction>

	<cffunction name="agencyEVVTransmissionIsAutoSend" access="public" returntype="boolean" output="false">
		<cfargument name="agencyID" type="numeric" required="true">
		<cfreturn getAgencyEVVTransmissionMode(arguments.agencyID) EQ "auto_send">
	</cffunction>

	<cffunction name="agencyUsesManualEVVTransmission" access="public" returntype="boolean" output="false">
		<cfargument name="agencyID" type="numeric" required="true">
		<cfreturn getAgencyEVVTransmissionMode(arguments.agencyID) EQ "manual_trans">
	</cffunction>

	<!--- Manual transmission report: drop row after payer accepts (HHA Success or Sandata Transaction Received) --->
	<cffunction name="visitEVVAcceptedForManualReport" access="public" returntype="boolean" output="false">
		<cfargument name="statusText" type="string" required="true">
		<cfset var s = uCase(trim(arguments.statusText))>
		<cfreturn (
			find("TRANSACTION RECEIVED", s) GT 0
			OR s EQ "SUCCESS"
			OR s EQ "SUCCESSFUL"
		)>
	</cffunction>
	
</cfcomponent>
