--[[
    Cerebro - Command Registry: Sync Commands
    Extracted from UI/CommandRegistry.lua (Phase 2a decomposition)

    Commands:
      sync_data       (original lines 260-291)
      version_check   (original lines 292-308)
      sync_reset      (original lines 309-344)
      sync_status     (original lines 346-449)
      sync_audit      (original lines 451-468)
      sync_history    (original lines 470-493)
      sync_check      (original lines 495-519)
      debug_hash      (original lines 520-536)

    @module UI.Commands.Sync
    @version 0.12.0
]]--

local AddonName, PrivateTable = ...
local Cerebro = LibStub("AceAddon-3.0"):GetAddon(AddonName)

Cerebro._commandDefs = Cerebro._commandDefs or {}
local defs = Cerebro._commandDefs

-- Communication Commands
defs[#defs + 1] = {
	id = "sync_data",
	displayName = "Force Sync",
	description = "Syncs EPGP data to/from raid (Officers push, Raiders request)",
	officerOnly = false,
	slash = "/cb sync",
	handler = function(ctx)
		-- Quarantine check with user-friendly message
		if Cerebro:IsQuarantined() then
			Cerebro:Print("|cffff8800Sync blocked:|r Quarantine active (recent reset).")
			Cerebro:Print("Use /cb quarantine to check status or /cb quarantine clear to override.")
			return
		end

		if Cerebro:IsOfficer() then
			Cerebro:RepairDatabase()
			if Cerebro.modules.CommunicationV2 then
				local sent = Cerebro.modules.CommunicationV2:SyncToRaid()
				if sent then
					Cerebro:Print("Data synced to raid (Officer push).")
				else
					Cerebro:Print("|cffff8800Sync deferred until combat ends.|r")
				end
			end
		else
			if Cerebro.modules.CommunicationV2 then
				Cerebro.modules.CommunicationV2:RequestSync()
			end
			Cerebro:Print("Sync requested from officers...")
		end
	end
}

defs[#defs + 1] = {
	id = "version_check",
	displayName = "Version Check",
	description = "Scans guild for Cerebro versions and reports outdated clients",
	officerOnly = true,
	hidden = false,
	dangerous = false,
	aliases = {"versioncheck", "vercheck"},
	slash = "/cb versioncheck",
	handler = function(ctx)
		if Cerebro.modules.CommunicationV2 then
			Cerebro.modules.CommunicationV2:VersionCheck()
		else
			Cerebro:Print("Communication module not loaded.")
		end
	end
}

defs[#defs + 1] = {
	id = "sync_reset",
	displayName = "Force Full Sync Reset",
	description = "Clears all delta sync state and forces immediate full sync to all clients",
	officerOnly = true,
	hidden = false,
	dangerous = false,
	aliases = {"syncreset"},
	slash = "/cb syncreset",
	handler = function(ctx)
		-- Clear delta sync state
		local s = Cerebro.db.global.syncState
		if s then
			s.pendingSyncs = {}
			s.dirtyPlayers = {}
			s.lastFullSyncAt = 0  -- Force full sync on next SyncToRaid
			s.dirtyRetainUntil = nil
		end

		-- Force immediate full sync
		if Cerebro.modules.CommunicationV2 then
			Cerebro:RecalculateAllPR()
			local sent = Cerebro.modules.CommunicationV2:SyncToRaid()
			if sent then
				Cerebro:Print("|cff00ff00Sync state reset.|r Full sync sent to all clients.")
			else
				Cerebro:Print("|cff00ff00Sync state reset.|r |cffff8800Full sync deferred until combat ends.|r")
			end
		end

		-- Audit log
		if Cerebro.Ledger then
			Cerebro.Ledger:AddAuditLog("SYNC_RESET", "Forced full sync by " .. (ctx.sender or "officer"))
		end
	end
}

-- Sync Status (Officer)
defs[#defs + 1] = {
	id = "sync_status",
	displayName = "Sync Status",
	description = "Shows sync health for all raid members (Officer only)",
	officerOnly = true,
	hidden = false,
	dangerous = false,
	aliases = {"syncstatus"},
	slash = "/cb syncstatus",
	handler = function(ctx, argv)
		if not IsInRaid() then
			Cerebro:Print("Not in a raid group. Sync status requires an active raid.")
			return
		end

		local numMembers = GetNumGroupMembers()
		local freshCount, staleCount, unknownSyncCount = 0, 0, 0
		local lines = {}
		local s = Cerebro.db.global.syncState or {}
		local peerStatus = s.peerStatus or {}

		for i = 1, numMembers do
			local name, _, _, _, class = GetRaidRosterInfo(i)
			if name then
				local fullName = Cerebro:GetFullPlayerName(name)
				local pData = Cerebro.db.global.players and Cerebro.db.global.players[fullName]
				local peer = peerStatus[fullName]

				-- DB status column
				local dbStatus
				if pData then
					if pData.status == "Core" then
						dbStatus = "|cff00ff00Core|r"
					else
						dbStatus = "|cffff8800" .. (pData.status or "?") .. "|r"
					end
				else
					dbStatus = "|cff888888no DB|r"
				end

				-- Freshness column (from peer tracking)
				local freshIcon, freshLabel, latencyStr
				if peer and peer.freshness then
					if peer.freshness == "FRESH" then
						freshIcon = "|cff00ff00\226\156\147|r"
						freshLabel = "|cff00ff00FRESH|r"
						freshCount = freshCount + 1
					elseif peer.freshness == "STALE" then
						freshIcon = "|cffff4444\226\156\151|r"
						freshLabel = "|cffff4444STALE|r"
						staleCount = staleCount + 1
					else
						freshIcon = "|cff888888?|r"
						freshLabel = "|cff888888UNKNOWN|r"
						unknownSyncCount = unknownSyncCount + 1
					end
					-- Show latency if available
					if peer.avgAckLatencyMs and peer.avgAckLatencyMs > 0 then
						latencyStr = string.format(" |cffaaaaaa(~%dms)|r", peer.avgAckLatencyMs)
					else
						latencyStr = ""
					end
				else
					freshIcon = "|cff888888?|r"
					freshLabel = "|cff888888no ACK|r"
					latencyStr = ""
					unknownSyncCount = unknownSyncCount + 1
				end

				local coloredName = Cerebro:ColorPlayerName(fullName, class)
				table.insert(lines, string.format("  %s %s  %s  %s%s",
					freshIcon, coloredName, dbStatus, freshLabel, latencyStr))
			end
		end

		-- Header
		Cerebro:Print(string.format("=== Raid Sync Status (%d members) ===", numMembers))

		-- Last broadcast info
		if (s.lastBroadcastAt or 0) > 0 then
			local age = time() - s.lastBroadcastAt
			local ageStr
			if age < 60 then
				ageStr = age .. "s ago"
			elseif age < 3600 then
				ageStr = math.floor(age / 60) .. "m ago"
			else
				ageStr = math.floor(age / 3600) .. "h ago"
			end
			Cerebro:Print("  Last broadcast: seq " .. (s.lastBroadcastSeq or "?") .. " (" .. ageStr .. ")")
		end

		-- Sort and print lines
		table.sort(lines)
		for _, line in ipairs(lines) do
			Cerebro:Print(line)
		end

		-- Summary
		Cerebro:Print(string.format("  Sync: |cff00ff00%d FRESH|r, |cffff4444%d STALE|r, |cff888888%d UNKNOWN|r",
			freshCount, staleCount, unknownSyncCount))
	end
}

-- Sync Audit (Diagnostic)
defs[#defs + 1] = {
	id = "sync_audit",
	displayName = "Sync Audit",
	description = "Compares per-player data across all online guild members to find sync discrepancies (Officer only)",
	officerOnly = true,
	hidden = false,
	dangerous = false,
	aliases = {"syncaudit"},
	slash = "/cb syncaudit",
	handler = function(ctx)
		if Cerebro.modules.CommunicationV2 then
			Cerebro.modules.CommunicationV2:RequestSyncAudit()
		else
			Cerebro:Print("Communication module not loaded.")
		end
	end
}

-- Sync History (Officer) - retroactive force-push of full transaction log
defs[#defs + 1] = {
	id = "sync_history",
	displayName = "Sync History",
	description = "Force-pushes your full transaction log to all online officers (retroactive catch-up)",
	officerOnly = true,
	hidden = false,
	dangerous = false,
	aliases = {"synchistory"},
	slash = "/cb synchistory",
	handler = function(ctx)
		if not Cerebro:IsOfficer() then
			Cerebro:Print("Officer permission required.")
			return
		end
		if not Cerebro.modules.CommunicationV2 then
			Cerebro:Print("Communication module not loaded.")
			return
		end
		local count = #(Cerebro.db.global.transactions or {})
		Cerebro:Print(string.format("Pushing %d history entries to officers...", count))
		Cerebro.modules.CommunicationV2:BroadcastAllTransactions()
	end
}

-- Sync Check (V1 Transport — uses same proven guild broadcast as VersionCheck)
defs[#defs + 1] = {
	id = "sync_check",
	displayName = "Sync Check",
	description = "Broadcasts sync check via V1 channel, collects peer hash responses for 5 seconds, reports convergence. Auto-syncs divergent peers.",
	officerOnly = true,
	hidden = false,
	dangerous = false,
	aliases = {"synccheck"},
	slash = "/cb synccheck",
	handler = function(ctx)
		local v2 = Cerebro.modules.CommunicationV2
		if not v2 then
			Cerebro:Print("|cffff0000Error:|r CommunicationV2 module not loaded.")
			return
		end

		if not IsInGuild() then
			Cerebro:Print("|cffff8800Not in guild.|r Sync check requires online peers.")
			return
		end

		-- V2: Send heartbeat to discover peers, then check for divergence
		v2:SendHeartbeat()
		Cerebro:Print("|cff00ff00[Sync Check]|r Heartbeat sent. Checking peer hashes...")

		-- After 3 seconds, check for stale/divergent peers and initiate repair
		Cerebro:ScheduleTimer(function()
			local stalePeers = v2:GetStalePeers()
			if not stalePeers or #stalePeers == 0 then
				Cerebro:Print("|cff00ff00[Sync Check]|r No divergent peers detected. All synced.")
			else
				local names = {}
				for _, p in ipairs(stalePeers) do names[#names + 1] = p end
				Cerebro:Print(string.format("|cffff8800[Sync Check]|r %d divergent peer(s): %s",
					#names, table.concat(names, ", ")))
				local myHash = v2:ComputeRosterHash()
				v2:StartRepairCycle(stalePeers, myHash, "Manual sync check")
			end
		end, 3)
	end
}

defs[#defs + 1] = {
	id = "debug_hash",
	displayName = "Debug Hash",
	description = "Prints V2 roster/config hash inputs for cross-client debugging",
	officerOnly = false,
	hidden = false,
	dangerous = false,
	aliases = {"debughash"},
	slash = "/cb debughash",
	handler = function(ctx)
		if Cerebro.modules.CommunicationV2 then
			Cerebro.modules.CommunicationV2:DebugHash()
		else
			Cerebro:Print("Communication module not loaded.")
		end
	end
}
