#!/usr/bin/env python3
"""Pure process-filtering rules used by application and adapter layers."""

from dataclasses import dataclass
from typing import Any, Dict, List, Optional


def normalize_query(query: str) -> str:
    """Normalize a search query for case-insensitive matching."""
    return query.strip().lower()


@dataclass(frozen=True)
class QueryTerm:
    """Single parsed search term."""

    field: Optional[str]
    value: str


SUPPORTED_FIELDS = {"name", "pid", "user", "gpu", "cmd", "status"}


def _parse_query_terms(query: str) -> List[QueryTerm]:
    """Parse query string into fielded/plain terms.

    Supported field syntax:
    - name:<text>
    - pid:<value>
    - user:<text>
    - gpu:<text|true|false>
    - cmd:<text>
    - status:<text>
    """
    normalized_query = normalize_query(query)
    if not normalized_query:
        return []

    terms: List[QueryTerm] = []
    for raw_term in normalized_query.split():
        if ":" not in raw_term:
            terms.append(QueryTerm(field=None, value=raw_term))
            continue

        field, raw_value = raw_term.split(":", 1)
        if field in SUPPORTED_FIELDS and raw_value:
            terms.append(QueryTerm(field=field, value=raw_value))
        else:
            # Treat unknown/invalid field tokens as plain terms for compatibility.
            terms.append(QueryTerm(field=None, value=raw_term))

    return terms


def _match_plain_term(process: Dict[str, Any], value: str) -> bool:
    """Match a plain term against common process fields."""
    haystacks = [
        str(process.get("name", "")),
        str(process.get("pid", "")),
        str(process.get("username", process.get("user", ""))),
        str(process.get("cmdline_summary", process.get("cmdline", ""))),
        str(process.get("status", "")),
    ]
    lowered = value.lower()
    return any(lowered in entry.lower() for entry in haystacks)


def _match_field_term(process: Dict[str, Any], term: QueryTerm) -> bool:
    """Match a fielded term against a process dictionary."""
    if term.field is None:
        return _match_plain_term(process, term.value)

    if term.field == "name":
        return term.value in str(process.get("name", "")).lower()

    if term.field == "pid":
        return term.value in str(process.get("pid", ""))

    if term.field == "user":
        user_value = str(process.get("username", process.get("user", ""))).lower()
        return term.value in user_value

    if term.field == "cmd":
        command_value = str(
            process.get("cmdline_summary", process.get("cmdline", ""))
        ).lower()
        return term.value in command_value

    if term.field == "status":
        return term.value in str(process.get("status", "")).lower()

    if term.field == "gpu":
        if term.value in {"true", "yes", "1"}:
            return bool(process.get("is_gpu_process", False))
        if term.value in {"false", "no", "0"}:
            return not bool(process.get("is_gpu_process", False))
        gpu_haystacks = [
            str(process.get("gpu_name", "")),
            str(process.get("gpu_vendor", "")),
            str(process.get("gpu", "")),
        ]
        return any(term.value in value.lower() for value in gpu_haystacks)

    return _match_plain_term(process, term.value)


def process_matches_query(process: Dict[str, Any], query: str) -> bool:
    """Return True when a process matches the given query.

    Query is split into space-separated terms and all terms must match.
    """
    terms = _parse_query_terms(query)
    if not terms:
        return True

    return all(_match_field_term(process, term) for term in terms)


def filter_processes(
    processes: List[Dict[str, Any]], query: str
) -> List[Dict[str, Any]]:
    """Filter process dictionaries by name or PID substring match."""
    normalized_query = normalize_query(query)
    if not normalized_query:
        return processes

    return [
        process
        for process in processes
        if process_matches_query(process, normalized_query)
    ]


__all__ = [
    "QueryTerm",
    "SUPPORTED_FIELDS",
    "filter_processes",
    "normalize_query",
    "process_matches_query",
]
