local Q=require(script.Parent.Parent.Promise)local n=require(script.Parent.Layers.AccessLayer)local u=require(script.Parent.DocumentData)local y=require(script.Parent.Error)local V=(require(script.Parent.stackSkipAssert)).stackSkipAssert local h={}h.__index=h function h.new(Q,n)return setmetatable({collection=Q,name=n;_data=nil},h)end function h.readyPromise(V)if V._readyPromise==nil then V._readyPromise=Q.new(function(Q,h)V._data=u.new({lockSession=n.acquireLockSession(V.collection.name,V.name,V.collection._migrations);collection=V.collection})local b,J=V.collection:validateData(V._data:read())if not b then h(y.new({kind=y.Kind.SchemaValidationFailed,error=J,context=("\083\099\104\101\109\097 \118\097\108\105\100\097\116\105\111\110 \102\097\105\108\101\100 \119\104\101\110 \108\111\097\100\105\110\103 \100\097\116\097 \105\110 \099\111\108\108\101\099\116\105\111\110 \037\113 \107\101\121 \037\113"):format(V.collection.name,V.name)}))end Q(V)end)end return Q.resolve(V._readyPromise)end function h.get(n,Q)Q=tostring(Q)V(n.collection:keyExists(Q),("\075\101\121 \037\113 \100\111\101\115 \110\111\116 \097\112\112\101\097\114 \105\110 \037\113\'\115 \115\099\104\101\109\097\046"):format(Q,n.collection.name))return(n._data:read())[Q]end function h.set(u,Q,n)V(u._data:isClosed()==false,"\065\116\116\101\109\112\116 \116\111 \099\097\108\108 \058\115\101\116\040\041 \111\110 \097 \099\108\111\115\101\100 \068\111\099\117\109\101\110\116")Q=tostring(Q)V(u.collection:validateKey(Q,n))local y=u._data:read()y[Q]=n u._data:write(y)end function h.save(n)V(n._data:isClosed()==false,"\065\116\116\101\109\112\116 \116\111 \099\097\108\108 \058\115\097\118\101\040\041 \111\110 \097 \099\108\111\115\101\100 \068\111\099\117\109\101\110\116")return Q.new(function(Q)n._data:save()Q()end)end function h.close(n)V(n._data:isClosed()==false,"\065\116\116\101\109\112\116 \116\111 \099\097\108\108 \058\099\108\111\115\101\040\041 \111\110 \097 \099\108\111\115\101\100 \068\111\099\117\109\101\110\116")return(Q.new(function(Q)n._data:close()Q()end)):finally(function()n.collection:_removeDocument(n.name)end)end function h.isClosed(Q)return Q._data:isClosed()end return h
local Promise = require(script.Parent.Parent.Promise)
local AccessLayer = require(script.Parent.Layers.AccessLayer)
local DocumentData = require(script.Parent.DocumentData)
local Error = require(script.Parent.Error)
local stackSkipAssert = require(script.Parent.stackSkipAssert).stackSkipAssert

local Document = {}
Document.__index = Document

function Document.new(collection, name)
	return setmetatable({
		collection = collection;
		name = name;
		_data = nil;
	}, Document)
end

function Document:readyPromise()
	if self._readyPromise == nil then
		self._readyPromise = Promise.new(function(resolve, reject)
			self._data = DocumentData.new({
				lockSession = AccessLayer.acquireLockSession(self.collection.name, self.name, self.collection._migrations);
				collection = self.collection;
			})

			local schemaOk, schemaError = self.collection:validateData(self._data:read())

			if not schemaOk then
				reject(Error.new({
					kind = Error.Kind.SchemaValidationFailed,
					error = schemaError,
					context = ("Schema validation failed when loading data in collection %q key %q"):format(
						self.collection.name,
						self.name
					)
				}))
			end

			resolve(self)
		end)
	end

	-- Wrap in Promise.resolve to track unique consumers
	return Promise.resolve(self._readyPromise)
end

function Document:get(key)
	key = tostring(key)

	stackSkipAssert(self.collection:keyExists(key), ("Key %q does not appear in %q's schema."):format(
		key,
		self.collection.name
	))

	return self._data:read()[key]
end

function Document:set(key, value)
	stackSkipAssert(self._data:isClosed() == false, "Attempt to call :set() on a closed Document")

	key = tostring(key)

	stackSkipAssert(self.collection:validateKey(key, value))

	local current = self._data:read()
	current[key] = value
	self._data:write(current)
end

function Document:save()
	stackSkipAssert(self._data:isClosed() == false, "Attempt to call :save() on a closed Document")

	return Promise.new(function(resolve)
		self._data:save()
		resolve()
	end)
end

function Document:close()
	stackSkipAssert(self._data:isClosed() == false, "Attempt to call :close() on a closed Document")

	return Promise.new(function(resolve)
		self._data:close()
		resolve()
	end):finally(function()
		self.collection:_removeDocument(self.name)
	end)
end

function Document:isClosed()
	return self._data:isClosed()
end

return Document