#!/usr/bin/env bash
# Comprehensive tests for the state tool
# Tests state machine creation, transitions, and PDCA cycle implementation

#export PS4='\e[90m+${LINENO} in ${#BASH_SOURCE[@]}>${FUNCNAME[0]}:${BASH_SOURCE[@]##*/} \e[0m'
#set -x

level=$1
if [ -z "$level" ]; then
  level=1
fi
echo "starting: ${BASH_SOURCE[@]##*/} <LOG_LEVEL=$1>"

source this
source test.suite
source state

log.level $level

# Test machine name for isolation
TEST_MACHINE="TEST_STATE_$$"
PDCA_MACHINE="PDCA_TEST_$$"

# Cleanup function - use state.machine.delete to properly clear ghost refs
cleanup_test_machines() {
  # Use state.machine.delete to clear both state files AND current.state.machine.env refs
  state.machine.delete "$TEST_MACHINE" 2>/dev/null || true
  state.machine.delete "$PDCA_MACHINE" 2>/dev/null || true
}

# Cleanup before tests
cleanup_test_machines

# ============================================================================
# T1: Test state machine creation
# ============================================================================
test.case - "T1: Create state machine" \
  state machine.create $TEST_MACHINE
if state machine.exists $TEST_MACHINE; then
  create.result 0 "Machine created"
else
  create.result 1 "Machine not created"
fi
expect 0 "Machine created" "state.machine.create creates machine"

# ============================================================================
# T2: Test adding custom states
# ============================================================================
test.case - "T2: Add custom state 'step.one'" \
  state of $TEST_MACHINE add step.one silent
# Find the state we just added
if state find $TEST_MACHINE step.one id >/dev/null 2>&1; then
  create.result 0 "State added"
else
  create.result 1 "State not found"
fi
expect 0 "State added" "state.add adds custom state"

# ============================================================================
# T3: Test state.set - set state directly
# ============================================================================
test.case - "T3: Set state to 'setup' (state 2)" \
  state of $TEST_MACHINE set 2
source $CONFIG_PATH/current.state.machine.env
if [ "$state" = "2" ]; then
  create.result 0 "State set to 2"
else
  create.result 1 "State is $state, expected 2"
fi
expect 0 "State set to 2" "state.set changes current state"

# ============================================================================
# T4: Test state.find by name
# ============================================================================
test.case - "T4: Find state by name 'initialized'" \
  state find $TEST_MACHINE initialized id
FOUND_ID=$(state find $TEST_MACHINE initialized id 2>/dev/null)
if [ "$FOUND_ID" = "1" ]; then
  create.result 0 "Found at ID 1"
else
  create.result 1 "Found at ID $FOUND_ID, expected 1"
fi
expect 0 "Found at ID 1" "state.find returns correct ID"

# ============================================================================
# T5: Test state transitions (numbers jump to other states)
# ============================================================================
# State [5] = 11 in default template, should transition to state 11
test.case - "T5: Transition states (number values)" \
  state find $TEST_MACHINE 5
# When finding state 5, it should show transition to 11
TRANSITION_RESULT=$(state find $TEST_MACHINE 5 2>/dev/null | head -1)
if echo "$TRANSITION_RESULT" | grep -q "11\|next.custom.state"; then
  create.result 0 "Transition detected"
else
  create.result 1 "No transition: $TRANSITION_RESULT"
fi
expect 0 "Transition detected" "Numeric states transition correctly"

# ============================================================================
# T6: Test machine deletion
# ============================================================================
test.case - "T6: Delete state machine" \
  state machine.delete $TEST_MACHINE
if ! state machine.exists $TEST_MACHINE 2>/dev/null; then
  create.result 0 "Machine deleted"
else
  create.result 1 "Machine still exists"
fi
expect 0 "Machine deleted" "state.machine.delete removes machine"

# ============================================================================
# PDCA State Machine Tests (T7-T10)
# ============================================================================

# PDCA test variables
export TEST_PDCA_ERRORS=0
export TEST_PDCA_ITERATION=0
export MAX_ITERATIONS=5

# PDCA private.check implementations
private.check.planning() {
  # Plan phase always succeeds, go to doing
  create.result 0 "Planning complete"
  return 0
}

private.check.doing() {
  # Do phase always succeeds, go to checking
  create.result 0 "Implementation complete"
  return 0
}

private.check.checking() {
  # Check phase: if errors exist, go to acting; else finished
  ((TEST_PDCA_ITERATION++))

  if [ "$TEST_PDCA_ITERATION" -ge "$MAX_ITERATIONS" ]; then
    create.result 0 "error.max.iterations"
    return 0
  fi

  if [ "$TEST_PDCA_ERRORS" -gt 0 ]; then
    create.result 0 "acting"  # Go to act phase
    return 0
  fi

  create.result 0 "finished"  # No errors, done!
  return 0
}

private.check.acting() {
  # Act phase: fix one error, then back to checking
  if [ "$TEST_PDCA_ERRORS" -gt 0 ]; then
    ((TEST_PDCA_ERRORS--))
  fi
  create.result 0 "checking"  # Always go back to check
  return 0
}

private.check.finished() {
  create.result 0 "PDCA cycle complete"
  return 0
}

private.check.error.max.iterations() {
  create.result 0 "Stopped at max iterations"
  return 0
}

# ============================================================================
# T7: PDCA happy path (no errors) - P→D→C→finished
# ============================================================================
cleanup_test_machines
TEST_PDCA_ERRORS=0
TEST_PDCA_ITERATION=0

test.case - "T7: PDCA happy path (no errors)" \
  state machine.create $PDCA_MACHINE

# Add PDCA states
state of $PDCA_MACHINE add planning silent
state of $PDCA_MACHINE add doing silent
state of $PDCA_MACHINE add checking silent
state of $PDCA_MACHINE add acting silent
state of $PDCA_MACHINE add finished silent
state of $PDCA_MACHINE add error.max.iterations silent

# Simulate P→D→C→finished
PDCA_PATH=""

# Planning
private.check.planning
PDCA_PATH="${PDCA_PATH}P"

# Doing
private.check.doing
PDCA_PATH="${PDCA_PATH}→D"

# Checking (no errors, should go to finished)
private.check.checking
PDCA_PATH="${PDCA_PATH}→C"

if [ "$RESULT" = "finished" ]; then
  PDCA_PATH="${PDCA_PATH}→finished"
  create.result 0 "P→D→C→finished"
else
  create.result 1 "Path: $PDCA_PATH, Result: $RESULT"
fi
expect 0 "P→D→C→finished" "PDCA with no errors goes directly to finished"

# ============================================================================
# T8: PDCA with 1 error - P→D→C→A→C→finished
# ============================================================================
TEST_PDCA_ERRORS=1
TEST_PDCA_ITERATION=0

test.case - "T8: PDCA with 1 error (C→A→C loop)" \
  echo "Starting PDCA with 1 error"

PDCA_PATH="P→D"

# Check finds error
private.check.checking
PDCA_PATH="${PDCA_PATH}→C"

if [ "$RESULT" = "acting" ]; then
  PDCA_PATH="${PDCA_PATH}→A"
  private.check.acting  # Fixes error, goes back to check

  private.check.checking  # Should find no errors now
  PDCA_PATH="${PDCA_PATH}→C"

  if [ "$RESULT" = "finished" ]; then
    PDCA_PATH="${PDCA_PATH}→finished"
    create.result 0 "$PDCA_PATH"
  else
    create.result 1 "Expected finished, got $RESULT"
  fi
else
  create.result 1 "Expected acting, got $RESULT"
fi
expect 0 "P→D→C→A→C→finished" "PDCA with 1 error: C→A→C→finished"

# ============================================================================
# T9: PDCA with 3 errors - P→D→C→A→C→A→C→A→C→finished
# ============================================================================
TEST_PDCA_ERRORS=3
TEST_PDCA_ITERATION=0

test.case - "T9: PDCA with 3 errors (multiple C→A loops)" \
  echo "Starting PDCA with 3 errors"

PDCA_PATH="P→D"
LOOP_COUNT=0

# Simulate the C→A loop
while true; do
  private.check.checking
  PDCA_PATH="${PDCA_PATH}→C"

  if [ "$RESULT" = "acting" ]; then
    private.check.acting
    PDCA_PATH="${PDCA_PATH}→A"
    ((LOOP_COUNT++))
  elif [ "$RESULT" = "finished" ]; then
    PDCA_PATH="${PDCA_PATH}→finished"
    break
  else
    break
  fi

  # Safety limit
  if [ "$LOOP_COUNT" -gt 10 ]; then
    break
  fi
done

if [ "$LOOP_COUNT" -eq 3 ] && echo "$PDCA_PATH" | grep -q "finished"; then
  create.result 0 "3 C→A loops completed"
else
  create.result 1 "Loops: $LOOP_COUNT, Path: $PDCA_PATH"
fi
expect 0 "3 C→A loops completed" "PDCA with 3 errors cycles 3 times"

# ============================================================================
# T10: PDCA max iterations guard
# ============================================================================
TEST_PDCA_ERRORS=100  # Many errors - should hit max iterations
TEST_PDCA_ITERATION=0

test.case - "T10: PDCA max iterations guard (prevents infinite loop)" \
  echo "Starting PDCA with 100 errors (should stop at $MAX_ITERATIONS)"

PDCA_PATH="P→D"
LOOP_COUNT=0
HIT_MAX=0

while true; do
  private.check.checking
  PDCA_PATH="${PDCA_PATH}→C"

  if [ "$RESULT" = "error.max.iterations" ]; then
    HIT_MAX=1
    PDCA_PATH="${PDCA_PATH}→MAX"
    break
  elif [ "$RESULT" = "acting" ]; then
    private.check.acting
    PDCA_PATH="${PDCA_PATH}→A"
    ((LOOP_COUNT++))
  elif [ "$RESULT" = "finished" ]; then
    break
  fi

  # Ultimate safety
  if [ "$LOOP_COUNT" -gt 20 ]; then
    break
  fi
done

if [ "$HIT_MAX" -eq 1 ]; then
  create.result 0 "Max iterations guard triggered"
else
  create.result 1 "Did not hit max: loops=$LOOP_COUNT"
fi
expect 0 "Max iterations guard triggered" "PDCA stops at max iterations"

# ============================================================================
# Cleanup
# ============================================================================
cleanup_test_machines

test.suite.save.results
