"""ND0504: Detect credential entries that leak credential metadata."""

from pathlib import Path
from typing import Any

from valn8n_lib.rules.registry import SourceMap, register
from valn8n_lib.source_map import lookup_line
from valn8n_lib.types import Diagnostic, Location, RuleCode, Severity, SuggestionLevel

_RULE_CODE = RuleCode("ND0504", Severity.WARNING)

_PLACEHOLDERS = {"credential-id", "XXXXXX"}


@register("ND0504", Severity.WARNING, description="Leaking credential in workflow", strict=False)
def check_leaking_credential(
    workflow: dict[str, Any],
    path: Path,
    source_map: SourceMap = None,
    suggestions: SuggestionLevel = SuggestionLevel.FULL,
) -> list[Diagnostic]:
    """Flag credential entries with valid IDs that leak credential metadata."""
    diagnostics: list[Diagnostic] = []
    fname = str(path)

    for i, node in enumerate(workflow.get("nodes", [])):
        if node.get("disabled"):
            continue

        node_creds = node.get("credentials")
        if not isinstance(node_creds, dict):
            continue

        node_name = node.get("name", f"node[{i}]")
        for cred_type, cred_value in node_creds.items():
            if not isinstance(cred_value, dict):
                continue
            cred_id = cred_value.get("id")
            # Skip if empty/missing (ND0502) or placeholder (ND0503)
            if not cred_id:
                continue
            if cred_id in _PLACEHOLDERS:
                continue
            pointer = f"/nodes/{i}/credentials/{cred_type}/id"
            line = lookup_line(source_map, pointer)
            diagnostics.append(
                Diagnostic(
                    file=fname,
                    location=Location(node_name, f"credentials/{cred_type}"),
                    code=_RULE_CODE,
                    message=(
                        f'Credential "{cred_type}" with ID "{cred_id}" is present in workflow file'
                    ),
                    line=line,
                ),
            )

    return diagnostics
