from entities import *
from llm import *

# Detect victory
#
# Conditions:
# 1. Matching items have just been hidden and all items are hidden now
@llm_by_value
def memory_detectVictory(
  c: MemoryContext
) -> MemoryContext:
  if (
    c.recentField == "hiddenItems" and
    len(c.hiddenItems) == len(c.playfieldItems)
  ):
    c.victory = True
    c.recentField = "victory"
    return c

  c.recentField = None
  return c
#}

# Deselect mismatched items
#
# Conditions:
# 1. Two items are selected and they are of different groups
@llm_by_value
def memory_deselectMismatchedItems(
  c: MemoryContext
) -> MemoryContext:
  if (
    c.recentField == "selectedItems" and
    len(c.selectedItems) == 2 and
    c.playfieldItems[c.selectedItems[0]] != c.playfieldItems[c.selectedItems[1]]
  ):
    c.mismatchedItems.clear()
    c.mismatchedItems.append(c.selectedItems[0])
    c.mismatchedItems.append(c.selectedItems[1])
    c.recentField = "mismatchedItems"
    return c

  c.recentField = None
  return c
#}

# Generate constant playfield suitable for testing and debugging
@llm_by_value
def memory_generateConstPlayfield(
  c: MemoryContext
) -> MemoryContext:
  idGroups: dict[int, int] = { }
  id = 0
  for gid in range(0, c.playfieldSize):
    idGroups[id] = gid
    id += 1
    idGroups[id] = gid
    id += 1
  #}
  c.playfieldItems = idGroups
  c.recentField = "playfieldItems"
  return c
#}

# Hide matching selected items
#
# Conditions:
# 1. Two items are selected and they are of the same group
@llm_by_value
def memory_hideMatchingItems(
  c: MemoryContext
) -> MemoryContext:
  if (
    c.recentField == "selectedItems" and
    len(c.selectedItems) == 2 and
    c.playfieldItems[c.selectedItems[0]] == c.playfieldItems[c.selectedItems[1]]
  ):
    c.hiddenItems.append(c.selectedItems[0])
    c.hiddenItems.append(c.selectedItems[1])
    c.recentField = "hiddenItems"
    return c

  c.recentField = None
  return c
#}

# Select item
#
# Conditions:
# 1. There are already two selected items
# 2. Item has just been selected
@llm_by_value
def memory_selectItem(
  c: MemoryContext
) -> MemoryContext:
  if (
    len(c.selectedItems) == 2
  ):
    c.selectedItems = []
  
  if (
    c.recentField == "selectedId"
  ):
    c.selectedItems.append(c.selectedId)
    c.recentField = "selectedItems"
    return c

  c.recentField = None
  return c
#}

# Test.

def test_memory_generateConstPlayfield(
) -> str:
  c = memory_createEmptyContext()
  c.playfieldSize = 2
  c = memory_generateConstPlayfield(c)
  if (
    c.recentField == "playfieldItems" and
    len(c.playfieldItems) == 4 and
    c.playfieldItems[0] == 0 and
    c.playfieldItems[1] == 0 and
    c.playfieldItems[2] == 1 and
    c.playfieldItems[3] == 1
  ):
    return "OK: memory_generateConstPlayfield"
  #}
  return "ERR: memory_generateConstPlayfield"
#}

def test_memory_selectItem(
) -> str:
  c = memory_createEmptyContext()
  c.playfieldSize = 2
  c = memory_generateConstPlayfield(c)

  # Select the first item.
  c.selectedId = 0
  c.recentField = "selectedId"
  c = memory_selectItem(c)

  # See if it's in selectedItems now.
  if (
    c.recentField == "selectedItems" and
    len(c.selectedItems) == 1 and
    c.selectedItems[0] == 0
  ):
    return "OK: selectItem"
  #}
  return "ERR: selectItem"
#}

def test_selectTwoItems(
) -> str:
  c = memory_createEmptyContext()
  c.playfieldSize = 2
  c = memory_generateConstPlayfield(c)

  # Select the first two items.
  c.selectedId = 0
  c.recentField = "selectedId"
  c = memory_selectItem(c)
  c.selectedId = 1
  c.recentField = "selectedId"
  c = memory_selectItem(c)

  # See if it's both items are selected now.
  if (
    c.recentField == "selectedItems" and
    len(c.selectedItems) == 2 and
    c.selectedItems[0] == 0 and
    c.selectedItems[1] == 1
  ):
    return "OK: selectTwoItems"
  #}
  return "ERR: selectTwoItems"
#}

def test_selectThreeItems(
) -> str:
  c = memory_createEmptyContext()
  c.playfieldSize = 2
  c = memory_generateConstPlayfield(c)

  # Select three items.
  c.selectedId = 0
  c.recentField = "selectedId"
  c = memory_selectItem(c)
  c.selectedId = 1
  c.recentField = "selectedId"
  c = memory_selectItem(c)
  c.selectedId = 2
  c.recentField = "selectedId"
  c = memory_selectItem(c)

  # See if only one (last) item is selected now.
  if (
    c.recentField == "selectedItems" and
    len(c.selectedItems) == 1 and
    c.selectedItems[0] == 2
  ):
    return "OK: selectThreeItems"
  #}
  return "ERR: selectThreeItems"
#}

def test_memory_hideMatchingItems(
) -> str:
  c = memory_createEmptyContext()
  c.playfieldSize = 2
  c = memory_generateConstPlayfield(c)

  # Select two items of the same group.
  c.selectedId = 0
  c.recentField = "selectedId"
  c = memory_selectItem(c)
  c.selectedId = 1
  c.recentField = "selectedId"
  c = memory_selectItem(c)

  # Hide matching items.
  c = memory_hideMatchingItems(c)

  # See if the two selected items match.
  if (
    c.recentField == "hiddenItems" and
    len(c.hiddenItems) == 2 and
    c.hiddenItems[0] == 0 and
    c.hiddenItems[1] == 1
  ):
    return "OK: memory_hideMatchingItems"
  #}
  return "ERR: memory_hideMatchingItems"
#}

def test_memory_deselectMismatchedItems(
) -> str:
  c = memory_createEmptyContext()
  c.playfieldSize = 2
  c = memory_generateConstPlayfield(c)

  # Select two items of different groups.
  c.selectedId = 0
  c.recentField = "selectedId"
  c = memory_selectItem(c)
  c.selectedId = 2
  c.recentField = "selectedId"
  c = memory_selectItem(c)

  # Detect mismatching.
  c = memory_deselectMismatchedItems(c)

  # See if the two selected items do not match.
  if (
    c.recentField == "mismatchedItems" and
    len(c.mismatchedItems) == 2 and
    c.mismatchedItems[0] == 0 and
    c.mismatchedItems[1] == 2
  ):
    return "OK: memory_deselectMismatchedItems"
  #}
  return "ERR: memory_deselectMismatchedItems"
#}

def test_memory_detectVictory(
) -> str:
  c = memory_createEmptyContext()
  c.playfieldSize = 2
  c = memory_generateConstPlayfield(c)

  # Select the first two items of the same group.
  c.selectedId = 0
  c.recentField = "selectedId"
  c = memory_selectItem(c)
  c.selectedId = 1
  c.recentField = "selectedId"
  c = memory_selectItem(c)

  # Hide the first pair.
  c = memory_hideMatchingItems(c)

  # Select the last two items of the same group.
  c.selectedId = 2
  c.recentField = "selectedId"
  c = memory_selectItem(c)
  c.selectedId = 3
  c.recentField = "selectedId"
  c = memory_selectItem(c)

  # Hide the second pair.
  c = memory_hideMatchingItems(c)

  # Detect victory.
  c = memory_detectVictory(c)

  # See if victory has been detected.
  if (
    c.recentField == "victory" and
    c.victory == True
  ):
    return "OK: memory_detectVictory"
  #}
  return "ERR: memory_detectVictory"
#}

def test_passContextByValue(
) -> str:
  c = memory_createEmptyContext()
  c.playfieldSize = 2
  c = memory_generateConstPlayfield(c)

  c.selectedId = 0
  c.recentField = "selectedId"
  c1 = memory_selectItem(c)

  c.selectedId = 1
  c.recentField = "selectedId"
  c2 = memory_selectItem(c)

  # See if c1 and c2 have different recentField.
  if (
    c1.selectedId != c2.selectedId
  ):
    return "OK: passContextByValue"

  return "ERR: passContextByValue"
#}

