--[[----------------------------------------------------------------------------

ADOBE CONFIDENTIAL
------------------
Copyright 2025 Adobe
All Rights Reserved.

NOTICE: All information contained herein is, and remains
the property of Adobe and its suppliers, if any. The intellectual
and technical concepts contained herein are proprietary to Adobe
and its suppliers and are protected by all applicable intellectual
property laws, including trade secret and copyright laws.
Dissemination of this information or reproduction of this material
is strictly forbidden unless prior written permission is obtained
from Adobe.

------------------------------------------------------------------------------]]

if true then

	-- To test the DBSCAN implementation, you must define WF_DBSCAN within
	-- WFCoreInit.c. You must also add the following natives files to the
	-- wf_core target:
	--
	-- core/dbscan/WFDBSCANImp.cpp
	-- third_party/dbscan_tp/dbscan.cpp
	-- third_party/dbscan_tp/dbscan.hpp
	-- third_party/dbscan_tp/nanoflann.hpp
	--
	-- This is temporary, and should be removed after the DBSCAN submodule is
	-- integrated into the client repos.

	return {}

end

--------------------------------------------------------------------------------

	-- WF.core.self_test
local WFRxTestCase = require 'WFRxTestCase'

	-- WF.core.utils
local KSIdGenerator = require 'KSIdGenerator'
local WFDBSCAN = require 'WFDBSCAN'

--============================================================================--

local WFDBSCANTest = {}

--------------------------------------------------------------------------------

function WFDBSCANTest.rxTestBasic_2D( rxTest )

	-- Test Data Clustering Params

	local numClusters = 3
	local pointsPerCluster = 10
	local clusterRadius = 0.1 -- Small radius for clustering

	-- Define cluster centers

	local clusterCenters = {
		{ x = 1.0, y = 1.0 },
		{ x = 3.0, y = 3.0 },
		{ x = 5.0, y = 5.0 }
	}

	-- Generate the test data

	local data = {}

	for clusterIndex = 1, numClusters do

		local center = clusterCenters[ clusterIndex ]

		for i = 1, pointsPerCluster do

			local x = center.x + math.random() * clusterRadius - clusterRadius / 2
			local y = center.y + math.random() * clusterRadius - clusterRadius / 2
			table.insert( data, { x, y } )
	
		end
	
	end

	-- Run DBSCAN
	
	local clusters = WFDBSCAN.DBSCAN_2D( data, 0.2, 3 )

	-- Basic verification

	rxTest:expectEqual( true, #clusters > 0 ) -- Should find at least one cluster

end

--------------------------------------------------------------------------------

function WFDBSCANTest.rxTestBasic_3D( rxTest )

	-- Test Data Clustering Params

	local numClusters = 5
	local pointsPerCluster = 20
	local clusterRadius = 0.01 -- Small radius for clustering
	local timestampVariation = 1000 -- Small variation in timestamps

	local timestamp = os.time()

	-- Define cluster centers

	local clusterCenters = {
		{ lat = 37.7749, lon = -122.4194, timestamp = timestamp },
		{ lat = 34.0522, lon = -118.2437, timestamp = timestamp + 3600 },
		{ lat = 40.7128, lon = -74.0060, timestamp = timestamp + 7200 },
		{ lat = 51.5074, lon = -0.1278, timestamp = timestamp + 10800 },
		{ lat = 48.8566, lon = 2.3522, timestamp = timestamp + 14400 }
	}

	-- Generate the test data

	math.randomseed( os.time() ) -- Seed the random number generator

	local dataByDocId = {}

	-- Generate some clustered data

	for clusterIndex = 1, numClusters do

		local clusterCenter = clusterCenters[ clusterIndex ]

		for i = 1, pointsPerCluster do

			local docId = KSIdGenerator.uuidInLowercaseHex()
			timestamp = clusterCenter.timestamp + math.random() * timestampVariation - timestampVariation / 2
			local latitude = clusterCenter.lat + math.random() * clusterRadius - clusterRadius / 2
			local longitude = clusterCenter.lon + math.random() * clusterRadius - clusterRadius / 2

			dataByDocId[ docId ] = {
				timestamp,
				latitude,
				longitude
			}

		end

	end

	local clusters = WFDBSCAN.DBSCAN_3D( dataByDocId, 0.5, 5 )

	rxTest:expectEqual( true, #clusters > 0 )

end

--------------------------------------------------------------------------------

function WFDBSCANTest.rxTestDBSCANEdgeCases( rxTest )

	-- Test case 1: Empty input

	local emptyData = {}
	local emptyClusters = WFDBSCAN.DBSCAN_3D( emptyData, 0.5, 5 )
	rxTest:expectEqual( 0, #emptyClusters )

	-- Test case 2: Single point

	local singlePoint = {
		["doc1"] = { 1234567890, 37.7749, -122.4194 }
	}

	local singleClusters = WFDBSCAN.DBSCAN_3D( singlePoint, 0.5, 5 )
	rxTest:expectEqual( 0, #singleClusters ) -- Should be noise

	-- Test case 3: All points noise

	local noiseData = {}
	for i = 1, 10 do
		noiseData["doc" .. i] = {
			os.time() + i * 3600,
			37.7749 + math.random() * 10,
			-122.4194 + math.random() * 10
		}
	end

	local noiseClusters = WFDBSCAN.DBSCAN_3D( noiseData, 0.1, 5 ) -- Small eps to ensure no clusters
	rxTest:expectEqual( 0, #noiseClusters )

	-- Test case 4: Two distinct clusters

	local twoClustersData = {}

	-- First cluster

	for i = 1, 10 do
		twoClustersData["doc1_" .. i] = {
			os.time(),
			37.7749 + math.random() * 0.01,
			-122.4194 + math.random() * 0.01
		}
	end

	-- Second cluster

	for i = 1, 10 do
		twoClustersData["doc2_" .. i] = {
			os.time() + 3600,
			34.0522 + math.random() * 0.01,
			-118.2437 + math.random() * 0.01
		}
	end

	local twoClusters = WFDBSCAN.DBSCAN_3D( twoClustersData, 0.5, 5 )
	rxTest:expectEqual( 2, #twoClusters )

end

--------------------------------------------------------------------------------

return WFRxTestCase.wrapSuite( 'WFDBSCANTest', WFDBSCANTest )
