"""Tests for FRONT008 (loading-returns-null) and FRONT009 (eager-queries-no-defer)."""

import pytest
from pathlib import Path

from stablestack.checkers.frontend.loading_returns_null import LoadingReturnsNullChecker
from stablestack.checkers.frontend.eager_queries_no_defer import EagerQueriesNoDeferChecker


# ── Local fixtures (non-test names to avoid should_skip_file) ──

@pytest.fixture
def tsx_file(tmp_path: Path):
    def _create(content: str, name: str = "Component.tsx") -> Path:
        p = tmp_path / name
        p.write_text(content)
        return p
    return _create


@pytest.fixture
def jsx_file(tmp_path: Path):
    def _create(content: str, name: str = "Component.jsx") -> Path:
        p = tmp_path / name
        p.write_text(content)
        return p
    return _create


# ============================================================
# FRONT008: loading-returns-null
# ============================================================


class TestLoadingReturnsNull:
    @pytest.fixture
    def checker(self):
        return LoadingReturnsNullChecker()

    # --- Detection ---

    def test_detects_isLoading_return_null(self, checker, tsx_file):
        code = """\
export function UserList() {
  const { data, isLoading } = useQuery({ queryKey: ['users'], queryFn: fetchUsers });
  if (isLoading) return null;
  return <ul>{data.map(u => <li key={u.id}>{u.name}</li>)}</ul>;
}
"""
        findings = checker.check_file(tsx_file(code), code)
        assert len(findings) == 1
        assert findings[0].rule_id == "FRONT008"

    def test_detects_loading_return_null(self, checker, tsx_file):
        code = """\
export function UserList({ loading, data }) {
  if (loading) return null;
  return <div>{data}</div>;
}
"""
        findings = checker.check_file(tsx_file(code), code)
        assert len(findings) == 1

    def test_detects_ternary_null(self, checker, tsx_file):
        code = """\
export function Page() {
  const { data, isLoading } = useQuery({ queryKey: ['x'], queryFn: fetchX });
  return isLoading ? null : <Content data={data} />;
}
"""
        findings = checker.check_file(tsx_file(code), code)
        assert len(findings) == 1

    def test_detects_no_data_with_query_hook(self, checker, tsx_file):
        code = """\
export function Dashboard() {
  const { data } = useQuery({ queryKey: ['dash'], queryFn: fetchDash });
  if (!data) return null;
  return <div>{data.title}</div>;
}
"""
        findings = checker.check_file(tsx_file(code), code)
        assert len(findings) == 1

    def test_no_data_without_query_hook_ignored(self, checker, tsx_file):
        """!data return null without a query hook should not flag."""
        code = """\
export function InfoBox({ data }) {
  if (!data) return null;
  return <div>{data.title}</div>;
}
"""
        findings = checker.check_file(tsx_file(code), code)
        assert len(findings) == 0

    # --- Suppression ---

    def test_skips_test_files(self, checker, tmp_path):
        code = "if (isLoading) return null;"
        p = tmp_path / "Component.test.tsx"
        p.write_text(code)
        findings = checker.check_file(p, code)
        assert len(findings) == 0

    def test_skips_custom_hook(self, checker, tsx_file):
        """Custom hooks (useXxx) returning null is fine."""
        code = """\
function useAuth() {
  const { data, isLoading } = useQuery({ queryKey: ['auth'], queryFn: fetchAuth });
  if (isLoading) return null;
  return data;
}
"""
        findings = checker.check_file(tsx_file(code), code)
        assert len(findings) == 0

    def test_skips_comments(self, checker, tsx_file):
        code = """\
export function Page() {
  // if (isLoading) return null;
  return <div>Hello</div>;
}
"""
        findings = checker.check_file(tsx_file(code), code)
        assert len(findings) == 0

    # --- Edge cases ---

    def test_empty_file(self, checker, tsx_file):
        findings = checker.check_file(tsx_file(""), "")
        assert len(findings) == 0

    def test_skeleton_used_no_finding(self, checker, tsx_file):
        code = """\
export function Page() {
  const { data, isLoading } = useQuery({ queryKey: ['x'], queryFn: fetchX });
  if (isLoading) return <Skeleton />;
  return <div>{data}</div>;
}
"""
        findings = checker.check_file(tsx_file(code), code)
        assert len(findings) == 0

    def test_jsx_file_supported(self, checker, jsx_file):
        code = """\
export function Page() {
  if (isLoading) return null;
  return <div>Content</div>;
}
"""
        findings = checker.check_file(jsx_file(code), code)
        assert len(findings) == 1


# ============================================================
# FRONT009: eager-queries-no-defer
# ============================================================


class TestEagerQueriesNoDefer:
    @pytest.fixture
    def checker(self):
        return EagerQueriesNoDeferChecker()

    # --- Detection ---

    def test_detects_3_eager_queries(self, checker, tsx_file):
        code = """\
export function Dashboard() {
  const { data: users } = useQuery({ queryKey: ['users'], queryFn: fetchUsers });
  const { data: roles } = useQuery({ queryKey: ['roles'], queryFn: fetchRoles });
  const { data: perms } = useQuery({ queryKey: ['perms'], queryFn: fetchPerms });
  return <div>{users}{roles}{perms}</div>;
}
"""
        findings = checker.check_file(tsx_file(code), code)
        assert len(findings) == 1
        assert findings[0].rule_id == "FRONT009"
        assert "3" in findings[0].message

    def test_detects_4_eager_trpc_queries(self, checker, tsx_file):
        code = """\
export function Settings() {
  const { data: a } = trpc.team.getMembers.useQuery();
  const { data: b } = trpc.team.getSettings.useQuery();
  const { data: c } = trpc.team.getPermissions.useQuery();
  const { data: d } = trpc.team.getLogs.useQuery();
  return <div />;
}
"""
        findings = checker.check_file(tsx_file(code), code)
        assert len(findings) == 1
        assert "4" in findings[0].message

    # --- Suppression ---

    def test_no_flag_with_enabled(self, checker, tsx_file):
        code = """\
export function Dashboard() {
  const { data: users } = useQuery({ queryKey: ['users'], queryFn: fetchUsers });
  const { data: roles } = useQuery({ queryKey: ['roles'], queryFn: fetchRoles, enabled: !!users });
  const { data: perms } = useQuery({ queryKey: ['perms'], queryFn: fetchPerms });
  return <div />;
}
"""
        findings = checker.check_file(tsx_file(code), code)
        assert len(findings) == 0

    def test_no_flag_fewer_than_3(self, checker, tsx_file):
        code = """\
export function Page() {
  const { data: a } = useQuery({ queryKey: ['a'], queryFn: fetchA });
  const { data: b } = useQuery({ queryKey: ['b'], queryFn: fetchB });
  return <div />;
}
"""
        findings = checker.check_file(tsx_file(code), code)
        assert len(findings) == 0

    def test_skips_test_files(self, checker, tmp_path):
        code = """\
const { data: a } = useQuery({ queryKey: ['a'], queryFn: fetchA });
const { data: b } = useQuery({ queryKey: ['b'], queryFn: fetchB });
const { data: c } = useQuery({ queryKey: ['c'], queryFn: fetchC });
"""
        p = tmp_path / "Component.test.tsx"
        p.write_text(code)
        findings = checker.check_file(p, code)
        assert len(findings) == 0

    # --- Edge cases ---

    def test_empty_file(self, checker, tsx_file):
        findings = checker.check_file(tsx_file(""), "")
        assert len(findings) == 0

    def test_mixed_usequery_and_trpc(self, checker, tsx_file):
        code = """\
export function Page() {
  const { data: a } = useQuery({ queryKey: ['a'], queryFn: fetchA });
  const { data: b } = trpc.user.getProfile.useQuery();
  const { data: c } = useQuery({ queryKey: ['c'], queryFn: fetchC });
  return <div />;
}
"""
        findings = checker.check_file(tsx_file(code), code)
        assert len(findings) == 1
