local EnsureApiRegistry = rawget(_G, "LIDCOUNCIL_EnsureApiRegistry")
local API, INTERNAL_API
if type(EnsureApiRegistry) == "function" then
  API, INTERNAL_API = EnsureApiRegistry()
else
  API = rawget(_G, "LIDCOUNCIL_API")
  if type(API) ~= "table" then
    API = {}
    _G.LIDCOUNCIL_API = API
  end
  if type(API.__internal) ~= "table" then
    API.__internal = {}
  end
  INTERNAL_API = API.__internal
end

INTERNAL_API.LIDCOUNCIL_CreateProfileSyncStateStore_Impl = function(deps)
  deps = type(deps) == "table" and deps or {}

  local RootDB = deps.RootDB
  local TrimText = deps.TrimText
  local DeepCopy = deps.DeepCopy
  local NormalizeCharacterKey = deps.NormalizeCharacterKey
  local ExportLootProfileSnapshot = deps.ExportLootProfileSnapshot
  local ImportLootProfileSnapshot = deps.ImportLootProfileSnapshot

  local MAX_PERSISTED_BASELINES = 80
  local MAX_REPAIR_HISTORY = 30
  local DEFAULT_REPAIR_HISTORY_DEDUPE_WINDOW_SECONDS = 8
  local PERSISTED_BASELINE_SCHEMA_VERSION = 2
  local MAX_PERSISTED_BASELINE_AGE_SECONDS = 28 * 24 * 60 * 60
  local runtimeUndoByProfile = {}

  local function trim(value)
    if type(TrimText) == "function" then
      return TrimText(value)
    end
    local text = tostring(value or "")
    text = text:gsub("^%s+", "")
    text = text:gsub("%s+$", "")
    return text
  end

  local function copy(value)
    if type(DeepCopy) == "function" then
      return DeepCopy(value)
    end
    if type(value) ~= "table" then
      return value
    end
    local clone = {}
    for key, entry in pairs(value) do
      clone[key] = copy(entry)
    end
    return clone
  end

  local function now()
    if type(GetServerTime) == "function" then
      return tonumber(GetServerTime()) or 0
    end
    return tonumber(time and time() or 0) or 0
  end

  local function normalizeMemberKey(value)
    if type(NormalizeCharacterKey) == "function" then
      return NormalizeCharacterKey(value)
    end
    return trim(value)
  end

  local function ensureStore()
    local root = type(RootDB) == "function" and RootDB() or nil
    root.ui = type(root) == "table" and type(root.ui) == "table" and root.ui or {}
    root.ui.profileSyncState = type(root.ui.profileSyncState) == "table" and root.ui.profileSyncState or {}
    local store = root.ui.profileSyncState
    store.baselinesByKey = type(store.baselinesByKey) == "table" and store.baselinesByKey or {}
    store.repairHistory = type(store.repairHistory) == "table" and store.repairHistory or {}
    return store
  end

  local function buildBaselineKey(localProfileId, memberKey)
    local resolvedProfileId = string.lower(trim(localProfileId))
    local resolvedMemberKey = string.lower(normalizeMemberKey(memberKey))
    if resolvedProfileId == "" or resolvedMemberKey == "" then
      return ""
    end
    return resolvedProfileId .. "|" .. resolvedMemberKey
  end

  local function buildRevisionFingerprint(summary)
    summary = type(summary) == "table" and summary or {}
    return {
      profileId = trim(summary.profileId),
      settings = math.max(0, tonumber(summary.settings) or 0),
      permissions = math.max(0, tonumber(summary.permissions) or 0),
      loot = math.max(0, tonumber(summary.loot or summary.operational) or 0),
      session = math.max(0, tonumber(summary.session or summary.operational) or 0),
      settingsChecksum = trim(summary.settingsChecksum),
      permissionsChecksum = trim(summary.permissionsChecksum),
      lootChecksum = trim(summary.lootChecksum ~= "" and summary.lootChecksum or summary.operationalChecksum),
      sessionChecksum = trim(summary.sessionChecksum ~= "" and summary.sessionChecksum or summary.operationalChecksum),
    }
  end

  local function doFingerprintsMatch(left, right)
    left = buildRevisionFingerprint(left)
    right = buildRevisionFingerprint(right)
    if left.profileId ~= "" and right.profileId ~= "" and string.lower(left.profileId) ~= string.lower(right.profileId) then
      return false
    end
    for _, field in ipairs({
      "settings",
      "permissions",
      "loot",
      "session",
      "settingsChecksum",
      "permissionsChecksum",
      "lootChecksum",
      "sessionChecksum",
    }) do
      if tostring(left[field] or "") ~= tostring(right[field] or "") then
        return false
      end
    end
    return true
  end

  local function prunePersistedBaselines(store)
    local baselines = type(store) == "table" and type(store.baselinesByKey) == "table" and store.baselinesByKey or {}
    local ordered = {}
    for key, entry in pairs(baselines) do
      ordered[#ordered + 1] = {
        key = key,
        cachedAt = math.max(0, tonumber(type(entry) == "table" and entry.cachedAt or 0) or 0),
      }
    end
    table.sort(ordered, function(left, right)
      if left.cachedAt ~= right.cachedAt then
        return left.cachedAt > right.cachedAt
      end
      return tostring(left.key) < tostring(right.key)
    end)
    for index = MAX_PERSISTED_BASELINES + 1, #ordered do
      baselines[ordered[index].key] = nil
    end
  end

  local function rememberPersistedMemberBaseline(localProfileId, memberKey, revisionSummary, subchecksumState, patchManifestState)
    local key = buildBaselineKey(localProfileId, memberKey)
    if key == "" then
      return false
    end
    local store = ensureStore()
    store.baselinesByKey[key] = {
      schemaVersion = PERSISTED_BASELINE_SCHEMA_VERSION,
      localProfileId = trim(localProfileId),
      memberKey = normalizeMemberKey(memberKey),
      revisionSummary = buildRevisionFingerprint(revisionSummary),
      subchecksumState = copy(subchecksumState),
      patchManifestState = copy(patchManifestState),
      cachedAt = now(),
    }
    prunePersistedBaselines(store)
    return true
  end

  local function getPersistedMemberBaseline(localProfileId, memberKey, revisionSummary)
    local key = buildBaselineKey(localProfileId, memberKey)
    if key == "" then
      return nil
    end
    local store = ensureStore()
    local entry = type(store.baselinesByKey[key]) == "table" and store.baselinesByKey[key] or nil
    if type(entry) ~= "table" then
      return nil
    end
    if math.max(0, tonumber(entry.schemaVersion) or 0) ~= PERSISTED_BASELINE_SCHEMA_VERSION then
      store.baselinesByKey[key] = nil
      return nil
    end
    local cachedAt = math.max(0, tonumber(entry.cachedAt) or 0)
    if cachedAt <= 0 or (now() - cachedAt) > MAX_PERSISTED_BASELINE_AGE_SECONDS then
      store.baselinesByKey[key] = nil
      return nil
    end
    if type(revisionSummary) == "table" and not doFingerprintsMatch(entry.revisionSummary, revisionSummary) then
      return nil
    end
    return copy(entry)
  end

  local function recordRepairHistory(entry)
    entry = type(entry) == "table" and copy(entry) or {}
    local store = ensureStore()
    local history = store.repairHistory
    local skipIfRecentSame = entry.skipIfRecentSame == true
    local dedupeWindowSeconds = math.max(0, tonumber(entry.dedupeWindowSeconds) or DEFAULT_REPAIR_HISTORY_DEDUPE_WINDOW_SECONDS)
    entry.skipIfRecentSame = nil
    entry.dedupeWindowSeconds = nil
    entry.profileName = trim(entry.profileName)
    entry.sessionId = trim(entry.sessionId)
    entry.memberKey = normalizeMemberKey(entry.memberKey)
    entry.kind = trim(entry.kind)
    entry.summary = trim(entry.summary)
    entry.createdAt = math.max(0, tonumber(entry.createdAt) or now())
    entry.id = trim(entry.id)
    if entry.id == "" then
      entry.id = string.format("RPH-%d-%d", entry.createdAt, math.random(1000, 9999))
    end
    if skipIfRecentSame then
      local earliestCreatedAt = math.max(0, entry.createdAt - dedupeWindowSeconds)
      local entryFingerprint = table.concat({
        string.lower(entry.profileName),
        string.lower(entry.sessionId),
        string.lower(entry.memberKey),
        string.lower(entry.kind),
        entry.summary,
      }, "\31")
      for index = #history, 1, -1 do
        local existing = history[index]
        if type(existing) == "table" then
          local existingCreatedAt = math.max(0, tonumber(existing.createdAt) or 0)
          if existingCreatedAt < earliestCreatedAt then
            break
          end
          local existingFingerprint = table.concat({
            string.lower(trim(existing.profileName)),
            string.lower(trim(existing.sessionId)),
            string.lower(normalizeMemberKey(existing.memberKey)),
            string.lower(trim(existing.kind)),
            trim(existing.summary),
          }, "\31")
          if existingFingerprint == entryFingerprint then
            local updatedEntry = copy(existing)
            updatedEntry.profileName = entry.profileName
            updatedEntry.sessionId = entry.sessionId
            updatedEntry.memberKey = entry.memberKey
            updatedEntry.kind = entry.kind
            updatedEntry.summary = entry.summary
            updatedEntry.createdAt = math.max(existingCreatedAt, entry.createdAt)
            table.remove(history, index)
            history[#history + 1] = updatedEntry
            return copy(updatedEntry)
          end
        end
      end
    end
    history[#history + 1] = entry
    while #history > MAX_REPAIR_HISTORY do
      table.remove(history, 1)
    end
    return copy(entry)
  end

  local function getRepairHistory(profileName, sessionId)
    local resolvedProfileName = trim(profileName)
    local resolvedSessionId = trim(sessionId)
    local history = type(ensureStore().repairHistory) == "table" and ensureStore().repairHistory or {}
    local filtered = {}
    for index = #history, 1, -1 do
      local entry = history[index]
      if type(entry) == "table"
        and (resolvedProfileName == "" or trim(entry.profileName) == resolvedProfileName)
        and (resolvedSessionId == "" or trim(entry.sessionId) == resolvedSessionId) then
        filtered[#filtered + 1] = copy(entry)
      end
    end
    return filtered
  end

  local function pushUndoSnapshot(profileName, entry)
    local resolvedProfileName = trim(profileName)
    if resolvedProfileName == "" or type(ExportLootProfileSnapshot) ~= "function" then
      return false
    end
    local snapshotData = ExportLootProfileSnapshot(resolvedProfileName)
    if type(snapshotData) ~= "string" or snapshotData == "" then
      return false
    end
    runtimeUndoByProfile[resolvedProfileName] = runtimeUndoByProfile[resolvedProfileName] or {}
    local stack = runtimeUndoByProfile[resolvedProfileName]
    stack[#stack + 1] = {
      snapshotData = snapshotData,
      profileName = resolvedProfileName,
      profileId = trim(type(entry) == "table" and entry.profileId or ""),
      sourceCharacter = normalizeMemberKey(type(entry) == "table" and entry.memberKey or ""),
      summary = trim(type(entry) == "table" and entry.summary or ""),
      kind = trim(type(entry) == "table" and entry.kind or ""),
      createdAt = now(),
    }
    while #stack > 6 do
      table.remove(stack, 1)
    end
    return true
  end

  local function getUndoStatus(profileName)
    local resolvedProfileName = trim(profileName)
    local stack = runtimeUndoByProfile[resolvedProfileName]
    local last = type(stack) == "table" and stack[#stack] or nil
    return {
      available = type(last) == "table",
      count = type(stack) == "table" and #stack or 0,
      last = copy(last),
    }
  end

  local function undoLastRepair(profileName)
    local resolvedProfileName = trim(profileName)
    if resolvedProfileName == "" or type(ImportLootProfileSnapshot) ~= "function" then
      return false, "Undo is unavailable."
    end
    local stack = runtimeUndoByProfile[resolvedProfileName]
    local entry = type(stack) == "table" and stack[#stack] or nil
    if type(entry) ~= "table" then
      return false, "No repair undo snapshot is available."
    end
    local ok, result = ImportLootProfileSnapshot(resolvedProfileName, entry.snapshotData, {
      expectedProfileId = entry.profileId,
      sourceCharacter = entry.sourceCharacter,
    })
    if not ok then
      return false, result or "Undo import failed."
    end
    table.remove(stack, #stack)
    recordRepairHistory({
      profileName = resolvedProfileName,
      kind = "undo",
      memberKey = entry.sourceCharacter,
      summary = "Reverted the last host-side repair snapshot.",
      createdAt = now(),
    })
    return true, copy(entry)
  end

  return {
    RememberPersistedMemberBaseline = rememberPersistedMemberBaseline,
    GetPersistedMemberBaseline = getPersistedMemberBaseline,
    RecordRepairHistory = recordRepairHistory,
    GetRepairHistory = getRepairHistory,
    PushUndoSnapshot = pushUndoSnapshot,
    GetUndoStatus = getUndoStatus,
    UndoLastRepair = undoLastRepair,
  }
end
