/// <cts-enable />
/**
 * Test Pattern: Simple List
 *
 * Tests the core functionality of the simple-list pattern:
 * - Initial state (empty list)
 * - Adding items
 * - Deleting items
 * - Toggle indent
 * - Set indent directly
 * - Empty string handling
 *
 * Run: deno task ct test packages/patterns/simple-list/simple-list.test.tsx --verbose
 */
import { action, computed, pattern } from "commontools";
import SimpleListModule from "./simple-list.tsx";

export default pattern(() => {
  // Instantiate the simple list pattern with default empty list
  const list = SimpleListModule({});

  // ==========================================================================
  // Actions
  // ==========================================================================

  // Add items
  const action_add_first = action(() => {
    list.addItem.send({ text: "First item" });
  });

  const action_add_second = action(() => {
    list.addItem.send({ text: "Second item" });
  });

  const action_add_third = action(() => {
    list.addItem.send({ text: "Third item" });
  });

  // Empty/whitespace should be ignored
  const action_add_empty = action(() => {
    list.addItem.send({ text: "" });
  });

  const action_add_whitespace = action(() => {
    list.addItem.send({ text: "   " });
  });

  // Toggle indent on first item
  const action_toggle_indent_0 = action(() => {
    list.toggleIndent.send({ index: 0 });
  });

  // Set indent directly on second item
  const action_set_indent_1_true = action(() => {
    list.setIndent.send({ index: 1, indented: true });
  });

  const action_set_indent_1_false = action(() => {
    list.setIndent.send({ index: 1, indented: false });
  });

  // Delete middle item (index 1)
  const action_delete_1 = action(() => {
    list.deleteItem.send({ index: 1 });
  });

  // Delete first item (index 0)
  const action_delete_0 = action(() => {
    list.deleteItem.send({ index: 0 });
  });

  // Delete last remaining item
  const action_delete_last = action(() => {
    list.deleteItem.send({ index: 0 });
  });

  // Invalid index operations (should be no-ops)
  const action_toggle_invalid = action(() => {
    list.toggleIndent.send({ index: 999 });
  });

  const action_delete_invalid = action(() => {
    list.deleteItem.send({ index: -1 });
  });

  // ==========================================================================
  // Assertions
  // ==========================================================================

  // Initial state
  const assert_initial_empty = computed(() => {
    return list.items.filter(() => true).length === 0;
  });

  // After adding items
  const assert_has_one = computed(() => {
    return list.items.filter(() => true).length === 1;
  });

  const assert_first_text = computed(() => {
    return list.items[0]?.text === "First item";
  });

  const assert_first_not_indented = computed(() => {
    return list.items[0]?.indented === false;
  });

  const assert_first_not_done = computed(() => {
    return list.items[0]?.done === false;
  });

  const assert_has_two = computed(() => {
    return list.items.filter(() => true).length === 2;
  });

  const assert_has_three = computed(() => {
    return list.items.filter(() => true).length === 3;
  });

  // Empty string shouldn't add
  const assert_still_three = computed(() => {
    return list.items.filter(() => true).length === 3;
  });

  // After toggle indent on first item
  const assert_first_indented = computed(() => {
    return list.items[0]?.indented === true;
  });

  // After toggle again (back to not indented)
  const assert_first_not_indented_again = computed(() => {
    return list.items[0]?.indented === false;
  });

  // After setIndent on second item
  const assert_second_indented = computed(() => {
    return list.items[1]?.indented === true;
  });

  const assert_second_not_indented = computed(() => {
    return list.items[1]?.indented === false;
  });

  // After deleting middle item
  const assert_back_to_two = computed(() => {
    return list.items.filter(() => true).length === 2;
  });

  const assert_second_is_third = computed(() => {
    // After deleting "Second item", "Third item" should now be at index 1
    return list.items[1]?.text === "Third item";
  });

  // After deleting first item
  const assert_down_to_one = computed(() => {
    return list.items.filter(() => true).length === 1;
  });

  const assert_remaining_is_third = computed(() => {
    return list.items[0]?.text === "Third item";
  });

  // After deleting last item
  const assert_back_to_empty = computed(() => {
    return list.items.filter(() => true).length === 0;
  });

  // After invalid operations (should still be empty, no crash)
  const assert_still_empty = computed(() => {
    return list.items.filter(() => true).length === 0;
  });

  // ==========================================================================
  // Test Sequence
  // ==========================================================================
  return {
    tests: [
      // Initial state
      { assertion: assert_initial_empty },

      // Add items
      { action: action_add_first },
      { assertion: assert_has_one },
      { assertion: assert_first_text },
      { assertion: assert_first_not_indented },
      { assertion: assert_first_not_done },

      { action: action_add_second },
      { assertion: assert_has_two },

      { action: action_add_third },
      { assertion: assert_has_three },

      // Empty/whitespace ignored
      { action: action_add_empty },
      { assertion: assert_still_three },
      { action: action_add_whitespace },
      { assertion: assert_still_three },

      // Toggle indent
      { action: action_toggle_indent_0 },
      { assertion: assert_first_indented },
      { action: action_toggle_indent_0 },
      { assertion: assert_first_not_indented_again },

      // Set indent directly
      { action: action_set_indent_1_true },
      { assertion: assert_second_indented },
      { action: action_set_indent_1_false },
      { assertion: assert_second_not_indented },

      // Delete middle item
      { action: action_delete_1 },
      { assertion: assert_back_to_two },
      { assertion: assert_second_is_third },

      // Delete first item
      { action: action_delete_0 },
      { assertion: assert_down_to_one },
      { assertion: assert_remaining_is_third },

      // Delete last item
      { action: action_delete_last },
      { assertion: assert_back_to_empty },

      // Invalid operations should be no-ops
      { action: action_toggle_invalid },
      { assertion: assert_still_empty },
      { action: action_delete_invalid },
      { assertion: assert_still_empty },
    ],
    // Expose subject for debugging
    list,
  };
});
