"""Model of knitted structure as a set of crossing wales using artin braid groups.

This module provides the Wale_Braid class which represents complex cable knitting patterns as mathematical braid structures,
using concepts from algebraic topology to model how wales cross over and under each other.
"""

from typing import Generic, TypeVar

from knit_graphs.artin_wale_braids.Wale_Braid_Word import Wale_Braid_Word
from knit_graphs.artin_wale_braids.Wale_Group import Wale_Group
from knit_graphs.Loop import Loop

LoopT = TypeVar("LoopT", bound=Loop)


class Wale_Braid(Generic[LoopT]):
    """A model of knitted structure as a set of crossing wales using Artin braid groups.

    This class represents complex cable knitting patterns using mathematical braid theory,
    where wales are treated as strands in a braid and their crossings are represented as braid operations.
    This provides a formal mathematical framework for analyzing and manipulating cable patterns.

    Attributes:
        wale_groups (list[Wale_Group]): The collection of wale groups that participate in the braid structure.
        wale_words (list[Wale_Braid_Word]): The sequence of braid words that describe the crossing operations between wales.
    """

    def __init__(self, wale_groups: list[Wale_Group], wale_words: list[Wale_Braid_Word[LoopT]]) -> None:
        """Initialize a wale braid with the specified groups and braid words.

        Args:
            wale_groups (list[Wale_Group]): The wale groups that participate in this braid structure.
            wale_words (list[Wale_Braid_Word]): The sequence of braid words describing the crossing operations.
        """
        self.wale_groups: list[Wale_Group] = wale_groups
        self.wale_words: list[Wale_Braid_Word] = wale_words

    def reduce(self) -> None:
        """Simplify the braid by removing pairs of braid words that invert each other.

        This method modifies the wale_words list by identifying and removing adjacent pairs of braid words that are inverses of each other,
         effectively canceling out their operations to create a simplified but equivalent braid representation.
        """
        reduced_words: list[Wale_Braid_Word] = []
        remaining_words: list[Wale_Braid_Word] = [*self.wale_words[1:]]
        while len(remaining_words) > 0:
            if len(reduced_words) == 0:
                reduced_words.append(remaining_words.pop(0))
            else:
                next_word = remaining_words.pop(0)
                current_word = reduced_words[-1]
                if next_word.is_inversion(current_word):
                    reduced_words.pop()  # remove current word because its inverted
                else:
                    reduced_words.append(next_word)
        self.wale_words = reduced_words
