local DataStoreService = game:GetService("DataStoreService")
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")

local GameConfig = require(ReplicatedStorage.Shared.GameConfig)
local GridUtils = require(ReplicatedStorage.Shared.GridUtils)
local Logger = require(script.Parent.Logger)

local PlayerDataService = {}
PlayerDataService.__index = PlayerDataService

local store = DataStoreService:GetDataStore(GameConfig.DataStoreName)
local session = {}

local function buildDefaultState()
	local width, height = GridUtils.PlotSizeFromLevel(1)
	return {
		version = GameConfig.StateVersion,
		coins = 200,
		conveyorLevel = 1,
		plotLevel = 1,
		grid = { width = width, height = height, cells = {} },
		pendingEggTokens = {},
		nextTokenId = 1,
		conveyorOffers = {},
		lastOfferRefreshAt = 0,
	}
end

function PlayerDataService:Get(player)
	return session[player.UserId]
end

function PlayerDataService:Load(player)
	local key = tostring(player.UserId)
	local ok, result = pcall(function()
		return store:GetAsync(key)
	end)

	if not ok then
		Logger.Error("PlayerDataService", "DataStore load failed", { userId = player.UserId })
		return false, "DataStoreLoadFailed"
	end

	if result == nil then
		session[player.UserId] = buildDefaultState()
		return true, nil
	end

	if type(result) ~= "table" then
		Logger.Error("PlayerDataService", "Invalid saved data format", { userId = player.UserId })
		return false, "InvalidSavedState"
	end

	session[player.UserId] = result
	return true, nil
end

function PlayerDataService:Save(player)
	local state = session[player.UserId]
	if state == nil then
		return true, nil
	end

	local key = tostring(player.UserId)
	local ok = pcall(function()
		store:SetAsync(key, state)
	end)

	if not ok then
		Logger.Error("PlayerDataService", "DataStore save failed", { userId = player.UserId })
		return false, "DataStoreSaveFailed"
	end

	return true, nil
end

Players.PlayerRemoving:Connect(function(player)
	PlayerDataService:Save(player)
	session[player.UserId] = nil
end)

game:BindToClose(function()
	for _, player in ipairs(Players:GetPlayers()) do
		PlayerDataService:Save(player)
	end
end)

return PlayerDataService
