"""I-Logic Algebra

O(1) multiplication table for state composition.

Multiplication Table:
     | DIR  INV  SPI  ASP  ABS
-----+---------------------------
DIR  |  DIR  INV  SPI  ASP  ABS
INV  |  INV  DIR  ASP  SPI  ABS
SPI  |  SPI  ASP  INV  DIR  ABS
ASP  |  ASP  SPI  DIR  INV  ABS
ABS  |  ABS  ABS  ABS  ABS  ABS
"""
from __future__ import annotations

from typing import List, Tuple, Optional

from .states import ILogicState


def multiply(a: complex, b: complex) -> complex:
    """O(1) state composition via complex multiplication."""
    result = a * b
    return ILogicState.normalize(result)


def compose(states: List[complex]) -> Tuple[complex, int]:
    """O(N) path composition with early termination on ABSORBED.

    Args:
        states: List of I-Logic states to compose

    Returns:
        (final_state, steps_taken)
    """
    result = ILogicState.DIRECT
    for i, state in enumerate(states):
        result = multiply(result, state)
        if result == ILogicState.ABSORBED:
            return result, i + 1
    return result, len(states)


def detect_cycle(states: List[complex]) -> Tuple[bool, str, int]:
    """Detect if path cycles.

    Mathematical guarantee: period divides 4.

    Returns:
        (is_cycle, description, period)
    """
    result = ILogicState.DIRECT
    for i, state in enumerate(states):
        result = multiply(result, state)
        if result == ILogicState.ABSORBED:
            return False, "terminates", i + 1
        if result == ILogicState.DIRECT and i > 0:
            return True, "cycle", i + 1
    if len(states) >= 4:
        return True, "cycle (period <= 4)", 4
    return False, "incomplete (need more states)", len(states)


def get_inverse(state: complex) -> Optional[complex]:
    """Get multiplicative inverse of state."""
    if state == ILogicState.ABSORBED:
        return None
    inverses = {
        ILogicState.DIRECT: ILogicState.DIRECT,
        ILogicState.INVERSE: ILogicState.INVERSE,
        ILogicState.SPIRAL: ILogicState.ANTI_SPIRAL,
        ILogicState.ANTI_SPIRAL: ILogicState.SPIRAL,
    }
    return inverses.get(state)


def verify_algebra() -> bool:
    """Verify all algebraic properties hold.

    Returns True if all 5 tests pass.
    """
    I = ILogicState

    # Test 1: Closure (25 combinations)
    for a in I.ALL_STATES:
        for b in I.ALL_STATES:
            result = multiply(a, b)
            if result not in I.ALL_STATES:
                return False

    # Test 2: Associativity (125 combinations)
    for a in I.ALL_STATES:
        for b in I.ALL_STATES:
            for c in I.ALL_STATES:
                left = multiply(multiply(a, b), c)
                right = multiply(a, multiply(b, c))
                if left != right:
                    return False

    # Test 3: Identity
    for a in I.ALL_STATES:
        if multiply(I.DIRECT, a) != a or multiply(a, I.DIRECT) != a:
            return False

    # Test 4: Absorbing element
    for a in I.ALL_STATES:
        if multiply(I.ABSORBED, a) != I.ABSORBED or multiply(a, I.ABSORBED) != I.ABSORBED:
            return False

    # Test 5: Cycle period 4
    for state in I.NON_ZERO_STATES:
        current = state
        for _ in range(3):
            current = multiply(current, state)
        if current != I.DIRECT:
            return False

    return True
