import pytest

import pyparsing as pp

from snowcap import resources as res
from snowcap.identifiers import parse_URN, smart_split
from snowcap.parse import FullyQualifiedIdentifier
from snowcap.resource_name import ResourceName

IDENTIFIER_TEST_CASES = [
    ("tbl", ["tbl"]),
    ("schema.tbl", ["schema", "tbl"]),
    ("DB.SCHEMA", ["DB", "SCHEMA"]),
    ("db.schema.tbl", ["db", "schema", "tbl"]),
    ('"tbl"', ['"tbl"']),
    ('"schema"."tbl"', ['"schema"', '"tbl"']),
    ('"db"."schema"."tbl"', ['"db"', '"schema"', '"tbl"']),
    ('db."schema"."tbl"', ["db", '"schema"', '"tbl"']),
    ('"db".schema."tbl"', ['"db"', "schema", '"tbl"']),
    ('"db"."schema".tbl', ['"db"', '"schema"', "tbl"]),
    ('db."this.is:schema".tbl', ["db", '"this.is:schema"', "tbl"]),
    ("TITAN_CLASS_TEST.PUBLIC.BASIC_MODEL.USER", ["TITAN_CLASS_TEST", "PUBLIC", "BASIC_MODEL", "USER"]),
]


def test_parse_identifier():
    for test_case, result in IDENTIFIER_TEST_CASES:
        assert FullyQualifiedIdentifier.parse_string(test_case).as_list() == result


def test_parse_identifier_wrapped():
    for test_case, result in IDENTIFIER_TEST_CASES:
        assert pp.MatchFirst(FullyQualifiedIdentifier).parse_string(test_case).as_list() == result


def test_urn():
    urn = parse_URN("urn::ABCD123:storage_integration/GCS_INT")
    assert str(urn) == "urn::ABCD123:storage_integration/GCS_INT"

    assert urn == parse_URN(str(urn))
    assert urn == parse_URN("urn::ABCD123:storage_integration/gcs_int")
    assert hash(urn) == hash(parse_URN("urn::ABCD123:storage_integration/gcs_int"))


def test_resource_name():
    rn = ResourceName("test")
    assert str(rn) == "TEST"

    rn = ResourceName('"test"')
    assert str(rn) == '"test"'
    assert rn._quoted

    rn = ResourceName("foo@bar.com")
    assert str(rn) == '"foo@bar.com"'
    assert rn._quoted


def test_resource_name_equality_and_comparison():
    """Test ResourceName equality - covers case-insensitivity, quoting, and string comparison.

    Key behaviors tested:
    - Unquoted names are case-insensitive
    - Quoted names preserve inner case but compare case-insensitively
    - Quoted lowercase differs from unquoted (preserved exact identifier)
    - String comparison works bidirectionally
    - List membership works
    """
    # Case-insensitive comparison for unquoted names
    assert ResourceName("test") == ResourceName("TEST")

    # Inequality for different names
    assert ResourceName("test") != ResourceName("foo")

    # Quoted uppercase equals unquoted (both resolve to same identifier)
    assert ResourceName('"FOO"') == ResourceName("foo")

    # Quoted lowercase differs from unquoted uppercase (different identifiers in Snowflake)
    assert ResourceName("test") != ResourceName('"test"')

    # Bidirectional string comparison (case-insensitive)
    assert "foo" == ResourceName("FOO")
    assert ResourceName("FOO") == "foo"

    # List membership works
    assert "FOO" in [ResourceName("foo"), ResourceName("bar")]
    assert ResourceName("FOO") in ["foo", "bar"]


def test_parse_fully_qualified_schema():
    sch = res.Schema(name="DB.SCHEMA")
    assert sch.name == "SCHEMA"
    assert sch.container.name == "DB"

    sch = res.Schema.from_sql("CREATE SCHEMA IF NOT EXISTS DB.SCHEMA")
    assert sch.name == "SCHEMA"
    assert sch.container.name == "DB"

    # tbl = res.Table(name="DB.SCHEMA.TABLE", columns=[res.Column(name="ID", data_type="INT")])
    # assert tbl.name == "TABLE"
    # assert tbl.container.name == "SCHEMA"
    # assert tbl.container.container.name == "DB"


def test_smart_split():
    assert smart_split("simple?test?of?delimiting", "?") == ["simple", "test", "of", "delimiting"]
    assert smart_split("test whitespace works", " ") == ["test", "whitespace", "works"]
    assert smart_split('"test!with"!quotes', "!") == ['"test!with"', "quotes"]
    assert smart_split('"test...multiple"...delimiters', ".") == ['"test...multiple"', "", "", "delimiters"]
    assert smart_split("\"test.only\".'double.quotes'.work", ".") == ['"test.only"', "'double", "quotes'", "work"]
    assert smart_split('"test max" split works', " ", 1) == ['"test max"', "split works"]
    assert smart_split('test!escaping!\\"still!splits\\"', "!") == ["test", "escaping", '\\"still', 'splits\\"']
