# region PROBLEM
'''
<> LL: Prepend
Implement the prepend method for the LinkedList class.

The prepend method should add a new node with a given value to the beginning
of the linked list, updating the head attribute and the length attribute
accordingly.

Requirements:
    - Handle both empty-list and non-empty-list cases.
    - Create a new node with the given value and add it to the beginning.
    - Update the head attribute of the LinkedList correctly.
    - Update the length attribute to reflect the addition.
    - Return True on success.
'''

class Node:
    def __init__(self, value):
        self.value = value
        self.next = None


class LinkedList:
    def __init__(self, value):
        new_node = Node(value)
        self.head = new_node
        self.tail = new_node
        self.length = 1

    def print_list(self):
        temp = self.head
        while temp is not None:
            print(temp.value)
            temp = temp.next

    def append(self, value):
        new_node = Node(value)
        if self.length == 0:
            self.head = new_node
            self.tail = new_node
        else:
            self.tail.next = new_node
            self.tail = new_node
        self.length += 1
        return True

    def pop(self):
        if self.length == 0:
            return None
        temp = self.head
        pre = self.head
        while temp.next:
            pre = temp
            temp = temp.next
        self.tail = pre
        self.tail.next = None
        self.length -= 1
        if self.length == 0:
            self.head = None
            self.tail = None
        return temp
# endregion


# region SOLUTION

def prepend(self, value):
    new_node = Node(value)
    
    if self.length == 0:
        self.head = new_node
        self.tail = new_node 
        self.length = 1
    
    else:
        new_node.next = self.head
        self.head = new_node
        self.length = self.length + 1
    return True

LinkedList.prepend = prepend

# endregion


# region TESTS

def test_prepend_to_empty_list():
    ll = LinkedList(1)
    ll.head = None
    ll.tail = None
    ll.length = 0

    result = ll.prepend(5)
    assert result is True
    assert ll.head.value == 5
    assert ll.tail.value == 5
    assert ll.head is ll.tail
    assert ll.length == 1


def test_prepend_to_non_empty_list():
    ll = LinkedList(2)
    ll.append(3)

    result = ll.prepend(1)
    assert result is True
    assert ll.head.value == 1
    assert ll.head.next.value == 2
    assert ll.tail.value == 3
    assert ll.length == 3


def test_prepend_multiple_nodes():
    ll = LinkedList(3)
    ll.prepend(2)
    ll.prepend(1)

    assert ll.head.value == 1
    assert ll.head.next.value == 2
    assert ll.head.next.next.value == 3
    assert ll.tail.value == 3
    assert ll.tail.next is None
    assert ll.length == 3


def test_prepend_does_not_break_tail():
    ll = LinkedList(2)
    ll.append(3)
    old_tail = ll.tail

    ll.prepend(1)
    assert ll.tail is old_tail
    assert ll.tail.value == 3
    assert ll.tail.next is None


if __name__ == "__main__":
    import pytest

    raise SystemExit(pytest.main([__file__, "-v"]))

# endregion
