from __future__ import annotations

import ast
from hashlib import sha256

from app.modules.rag.indexing.code.entrypoints.registry import Entrypoint


class FastApiEntrypointDetector:
    _METHODS = {"get", "post", "put", "patch", "delete"}

    def detect(self, *, path: str, symbols: list) -> list[Entrypoint]:
        items: list[Entrypoint] = []
        for symbol in symbols:
            for decorator in symbol.decorators or []:
                route = _FastApiRouteParser().parse(decorator)
                if route is None:
                    continue
                method, route_path = route
                items.append(
                    Entrypoint(
                        entry_id=sha256(f"{path}|fastapi|{symbol.symbol_id}|{decorator}".encode("utf-8")).hexdigest(),
                        entry_type="http",
                        framework="fastapi",
                        route_or_command=f"{method} {route_path}",
                        handler_symbol_id=symbol.symbol_id,
                        path=path,
                        start_line=symbol.start_line,
                        end_line=symbol.end_line,
                        handler_symbol=symbol.qname,
                        declaring_symbol=_declaring_symbol(symbol.qname),
                        entrypoint_kind="http_route",
                        http_method=method,
                        route_path=route_path,
                        decorator_text=f"@{decorator}",
                        summary_text=_summary_text(method, route_path, symbol.qname),
                        metadata={"methods": [method]},
                    )
                )
        return items


class _FastApiRouteParser:
    def parse(self, decorator: str) -> tuple[str, str] | None:
        lowered = decorator.lower()
        tail = lowered.split(".")[-1].split("(", 1)[0]
        if tail not in FastApiEntrypointDetector._METHODS:
            return None
        method = tail.upper()
        route_path = self._route_path(decorator)
        return (method, route_path) if route_path else None

    def _route_path(self, decorator: str) -> str:
        try:
            expr = ast.parse(decorator, mode="eval").body
        except SyntaxError:
            return ""
        if not isinstance(expr, ast.Call) or not expr.args:
            return ""
        first = expr.args[0]
        if isinstance(first, ast.Constant) and isinstance(first.value, str):
            return first.value
        return ""


def _declaring_symbol(qname: str) -> str:
    parts = [item for item in qname.split(".") if item]
    if len(parts) >= 2:
        return parts[0]
    return qname


def _summary_text(method: str, route_path: str, handler_symbol: str) -> str:
    declaring = _declaring_symbol(handler_symbol)
    return f"{method} {route_path} declared in {declaring}"
