"""TwoWaySQLParser の WITH 句（CTE）テスト."""

from sqlym.parser.twoway import TwoWaySQLParser


class TestWithClauseBasic:
    """WITH 句の基本的なパラメータ置換."""

    def test_with_clause_param_substitution(self) -> None:
        """WITH 句内のパラメータが正しく置換される."""
        sql = """\
WITH active_users AS (
    SELECT * FROM users
    WHERE status = /* status */'active'
)
SELECT * FROM active_users"""
        parser = TwoWaySQLParser(sql)
        result = parser.parse({"status": "enabled"})
        assert "status = ?" in result.sql
        assert result.params == ["enabled"]

    def test_with_clause_and_main_query_params(self) -> None:
        """WITH 句とメインクエリの両方にパラメータがある場合."""
        sql = """\
WITH filtered AS (
    SELECT * FROM users
    WHERE status = /* status */'active'
)
SELECT * FROM filtered
WHERE dept_id = /* dept_id */1"""
        parser = TwoWaySQLParser(sql)
        result = parser.parse({"status": "enabled", "dept_id": 10})
        assert "status = ?" in result.sql
        assert "dept_id = ?" in result.sql
        assert result.params == ["enabled", 10]


class TestWithClauseRemoval:
    """WITH 句内での行削除."""

    def test_with_clause_line_removal(self) -> None:
        """WITH 句内で $param が None なら行削除."""
        sql = """\
WITH filtered AS (
    SELECT * FROM users
    WHERE
        status = /* $status */'active'
        AND dept_id = /* $dept_id */1
)
SELECT * FROM filtered"""
        parser = TwoWaySQLParser(sql)
        result = parser.parse({"status": "enabled", "dept_id": None})
        assert "status = ?" in result.sql
        assert "dept_id" not in result.sql
        assert result.params == ["enabled"]

    def test_with_clause_all_conditions_none(self) -> None:
        """WITH 句内の条件が全て None なら WHERE ごと削除、SELECT は残る."""
        sql = """\
WITH filtered AS (
    SELECT * FROM users
    WHERE
        status = /* $status */'active'
        AND dept_id = /* $dept_id */1
)
SELECT * FROM filtered"""
        parser = TwoWaySQLParser(sql)
        result = parser.parse({"status": None, "dept_id": None})
        # CTE 内の SELECT は保持され、WHERE のみ削除される
        assert "WITH" in result.sql
        assert "SELECT * FROM users" in result.sql
        assert "WHERE" not in result.sql
        assert result.params == []


class TestMultipleCTEs:
    """複数の CTE を持つ WITH 句."""

    def test_multiple_ctes_param_substitution(self) -> None:
        """複数 CTE でそれぞれパラメータ置換."""
        sql = """\
WITH
    active_users AS (
        SELECT * FROM users
        WHERE status = /* status */'active'
    ),
    departments AS (
        SELECT * FROM dept
        WHERE region = /* region */'east'
    )
SELECT * FROM active_users u
JOIN departments d ON u.dept_id = d.id"""
        parser = TwoWaySQLParser(sql)
        result = parser.parse({"status": "enabled", "region": "west"})
        assert "status = ?" in result.sql
        assert "region = ?" in result.sql
        assert result.params == ["enabled", "west"]

    def test_multiple_ctes_partial_removal(self) -> None:
        """複数 CTE で一部の条件が None."""
        sql = """\
WITH
    active_users AS (
        SELECT * FROM users
        WHERE
            status = /* $status */'active'
            AND role = /* $role */'admin'
    ),
    departments AS (
        SELECT * FROM dept
        WHERE region = /* $region */'east'
    )
SELECT * FROM active_users u
JOIN departments d ON u.dept_id = d.id"""
        parser = TwoWaySQLParser(sql)
        result = parser.parse({"status": "enabled", "role": None, "region": None})
        assert "status = ?" in result.sql
        assert "role" not in result.sql
        # region が None でも departments CTE 自体は残る（SELECT * FROM dept）
        assert "departments" in result.sql
        assert result.params == ["enabled"]


class TestWithClauseInClause:
    """WITH 句内での IN 句展開."""

    def test_with_clause_in_expansion(self) -> None:
        """WITH 句内で IN 句のリストパラメータが展開される."""
        sql = """\
WITH filtered AS (
    SELECT * FROM users
    WHERE dept_id IN /* $dept_ids */(1, 2, 3)
)
SELECT * FROM filtered"""
        parser = TwoWaySQLParser(sql)
        result = parser.parse({"dept_ids": [10, 20, 30]})
        assert "IN (?, ?, ?)" in result.sql
        assert result.params == [10, 20, 30]

    def test_with_clause_in_empty_list(self) -> None:
        """WITH 句内で非 removable IN 句に空リストを渡した場合."""
        sql = """\
WITH filtered AS (
    SELECT * FROM users
    WHERE dept_id IN /* dept_ids */(1, 2, 3)
)
SELECT * FROM filtered"""
        parser = TwoWaySQLParser(sql)
        result = parser.parse({"dept_ids": []})
        assert "IN (NULL)" in result.sql
        assert result.params == []

    def test_with_clause_in_removable_empty_list(self) -> None:
        """WITH 句内で $付き IN 句の空リストは行削除される."""
        sql = """\
WITH filtered AS (
    SELECT * FROM users
    WHERE dept_id IN /* $dept_ids */(1, 2, 3)
)
SELECT * FROM filtered"""
        parser = TwoWaySQLParser(sql)
        result = parser.parse({"dept_ids": []})
        # IN 句の空リストは IN (NULL) に変換（行削除ではない）
        assert "WITH" in result.sql
        assert "SELECT * FROM users" in result.sql
        assert "dept_id IN (NULL)" in result.sql


class TestWithClauseComplex:
    """WITH 句の複雑なケース."""

    def test_recursive_style_cte(self) -> None:
        """再帰 CTE 風の構文（UNION ALL あり）."""
        sql = """\
WITH RECURSIVE subordinates AS (
    SELECT id, name, manager_id
    FROM employees
    WHERE id = /* $root_id */1
    UNION ALL
    SELECT e.id, e.name, e.manager_id
    FROM employees e
    JOIN subordinates s ON e.manager_id = s.id
)
SELECT * FROM subordinates"""
        parser = TwoWaySQLParser(sql)
        result = parser.parse({"root_id": 100})
        assert "id = ?" in result.sql
        assert "UNION ALL" in result.sql
        assert result.params == [100]

    def test_with_clause_nested_conditions(self) -> None:
        """WITH 句内にネストした条件."""
        sql = """\
WITH filtered AS (
    SELECT * FROM users
    WHERE
        status = /* $status */'active'
        AND (
            role = /* $role1 */'admin'
            OR role = /* $role2 */'manager'
        )
)
SELECT * FROM filtered"""
        parser = TwoWaySQLParser(sql)
        result = parser.parse({"status": "enabled", "role1": None, "role2": None})
        assert "status = ?" in result.sql
        # 括弧内が全削除 → 括弧ごと削除
        assert "role" not in result.sql
        assert "(" not in result.sql or "()" not in result.sql
        assert result.params == ["enabled"]
