# pylint: disable=too-few-public-methods, import-error, missing-docstring, unnecessary-pass

# Disabled because of a bug with pypy 3.8 see
# https://github.com/pylint-dev/pylint/pull/7918#issuecomment-1352737369
# pylint: disable=multiple-statements

import six
from unknown import Unknown

TESTLIST = [1, 2, 3]
TESTTUPLE = (1, 2, 3)
TESTSTR = '123'

# getitem tests with bad indices
def function1():
    """list index is a function"""
    return TESTLIST[id] # [invalid-sequence-index]

def function2():
    """list index is None"""
    return TESTLIST[None] # [invalid-sequence-index]

def function3():
    """list index is a float expression"""
    return TESTLIST[float(0)] # [invalid-sequence-index]

def function4():
    """list index is a str constant"""
    return TESTLIST['0'] # [invalid-sequence-index]

def function5():
    """list index does not implement __index__"""
    class NonIndexType:
        """Class without __index__ method"""
        pass

    return TESTLIST[NonIndexType()] # [invalid-sequence-index]

def function6():
    """Tuple index is None"""
    return TESTTUPLE[None] # [invalid-sequence-index]

def function7():
    """String index is None"""
    return TESTSTR[None] # [invalid-sequence-index]

def function8():
    """Index of subclass of tuple is None"""
    class TupleTest(tuple):
        """Subclass of tuple"""
        pass
    return TupleTest()[None] # [invalid-sequence-index]

# getitem tests with good indices
def function9():
    """list index is an int constant"""
    return TESTLIST[0]  # no error

def function10():
    """list index is an integer expression"""
    return TESTLIST[int(0.0)] # no error

def function11():
    """list index is a slice"""
    return TESTLIST[slice(1, 2, 3)] # no error

def function12():
    """list index implements __index__"""
    class IndexType:
        """Class with __index__ method"""
        def __index__(self):
            """Allow objects of this class to be used as slice indices"""
            return 0

    return TESTLIST[IndexType()] # no error

def function13():
    """list index implements __index__ in a superclass"""
    class IndexType:
        """Class with __index__ method"""
        def __index__(self):
            """Allow objects of this class to be used as slice indices"""
            return 0

    class IndexSubType(IndexType):
        """Class with __index__ in parent"""
        pass

    return TESTLIST[IndexSubType()] # no error

def function14():
    """Tuple index is an int constant"""
    return TESTTUPLE[0]

def function15():
    """String index is an int constant"""
    return TESTSTR[0]

def function16():
    """Index of subclass of tuple is an int constant"""
    class TupleTest(tuple):
        """Subclass of tuple"""
        pass
    return TupleTest()[0] # no error

def function17():
    """Index of subclass of tuple with custom __getitem__ is None"""
    class TupleTest(tuple):
        """Subclass of tuple with custom __getitem__"""
        def __getitem__(self, index):
            """Allow non-integer indices"""
            return 0
    return TupleTest()[None] # no error

def function18():
    """Index of subclass of tuple with __getitem__ in superclass is None"""
    class TupleTest(tuple):
        """Subclass of tuple with custom __getitem__"""
        def __getitem__(self, index):
            """Allow non-integer indices"""
            return 0

    class SubTupleTest(TupleTest):
        """Subclass of a subclass of tuple"""
        pass

    return SubTupleTest()[None] # no error

# Test with set and delete statements
def function19():
    """Set with None and integer indices"""
    TESTLIST[None] = 0 # [invalid-sequence-index]
    TESTLIST[0] = 0 # no error

def function20():
    """Delete with None and integer indices"""
    del TESTLIST[None] # [invalid-sequence-index]
    del TESTLIST[0] # no error

def function21():
    """Set and delete on a subclass of list"""
    class ListTest(list):
        """Inherit all list get/set/del handlers"""
        pass
    test = ListTest()

    # Set and delete with invalid indices
    test[None] = 0 # [invalid-sequence-index]
    del test[None] # [invalid-sequence-index]

    # Set and delete with valid indices
    test[0] = 0 # no error
    del test[0] # no error

def function22():
    """Get, set, and delete on a subclass of list that overrides __setitem__"""
    class ListTest(list):
        """Override setitem but not get or del"""
        def __setitem__(self, key, value):
            pass
    test = ListTest()

    # failure on the getitem with None
    test[None][0] = 0 # [invalid-sequence-index]
    # failure on the getitem with None
    del test[None] # [invalid-sequence-index]

    test[0][0] = 0 # getitem with int and setitem with int, no error
    test[None] = 0 # setitem overridden, no error
    test[0] = 0 # setitem with int, no error
    del test[0] # delitem with int, no error

def function23():
    """Get, set, and delete on a subclass of list that overrides __delitem__"""
    class ListTest(list):
        """Override delitem but not get or set"""
        def __delitem__(self, key):
            pass
    test = ListTest()

    # failure on the getitem with None
    test[None][0] = 0 # [invalid-sequence-index]
    # setitem with invalid index
    test[None] = 0  # [invalid-sequence-index]

    test[0][0] = 0 # getitem with int and setitem with int, no error
    test[0] = 0 # setitem with int, no error
    del test[None] # delitem overridden, no error
    del test[0] # delitem with int, no error

def function24():
    """Get, set, and delete on a subclass of list that overrides __getitem__"""
    class ListTest(list):
        """Override gelitem but not del or set"""
        def __getitem__(self, key):
            pass
    test = ListTest()

    # setitem with invalid index
    test[None] = 0 # [invalid-sequence-index]
    # delitem with invalid index
    del test[None] # [invalid-sequence-index]

    test[None][0] = 0 # getitem overridden, no error
    test[0][0] = 0 # getitem with int and setitem with int, no error
    test[0] = 0 # setitem with int, no error
    del test[0] # delitem with int, no error

# Test ExtSlice usage
def function25():
    """Extended slice used with a list"""
    return TESTLIST[..., 0] # [invalid-sequence-index]

def function26():
    """Extended slice used with an object that implements __getitem__"""
    class ExtSliceTest:
        """Permit extslice syntax by implementing __getitem__"""
        def __getitem__(self, index):
            return 0
    return ExtSliceTest()[..., 0] # no error

def function27():
    """Don't warn in the case where the indexed object has unknown base classes."""
    class UnknownBase(Unknown):
        pass
    slices = UnknownBase["aaaa"] + UnknownBase()[object]
    ext_slices = UnknownBase[..., 0] + UnknownBase()[..., 0]
    return slices, ext_slices


def function28():
    """Don't emit for classes with the right implementation."""

    class Meta(type):
        def __getitem__(cls, arg):
            return 24

    @six.add_metaclass(Meta)
    class Works:
        pass

    @six.add_metaclass(Meta)
    class Error(list):
        pass

    return Works['hello'] + Error['hello']
