"""Compatibility helpers for phased embedding migration.

This module provides a small, stable API subset compatible with legacy
`sage.common.components.sage_embedding` call patterns used by downstream repos.
"""

from __future__ import annotations

import hashlib
import math
import re
from dataclasses import dataclass
from typing import Any

from .service import EmbeddingService


@dataclass(slots=True)
class _HashEmbedder:
    dim: int = 384

    def embed(self, text: str) -> list[float]:
        tokens = re.findall(r"[\w\u4e00-\u9fa5]+", text.lower()) or [text.lower()]
        vector = [0.0] * self.dim
        for token in tokens:
            digest = hashlib.sha256(token.encode("utf-8")).digest()
            for offset in range(0, len(digest), 4):
                idx = int.from_bytes(digest[offset : offset + 4], "little") % self.dim
                vector[idx] += 1.0
        norm = math.sqrt(sum(v * v for v in vector)) or 1.0
        return [v / norm for v in vector]

    def embed_batch(self, texts: list[str]) -> list[list[float]]:
        return [self.embed(text) for text in texts]

    def get_dim(self) -> int:
        return self.dim


@dataclass(slots=True)
class _MockEmbedder:
    dim: int = 128

    def embed(self, text: str) -> list[float]:
        seed = (sum(ord(ch) for ch in text) % 97) / 97.0
        return [seed for _ in range(self.dim)]

    def embed_batch(self, texts: list[str]) -> list[list[float]]:
        return [self.embed(text) for text in texts]

    def get_dim(self) -> int:
        return self.dim


@dataclass(slots=True)
class _EndpointEmbedder:
    service: EmbeddingService
    model: str | None = None
    dim: int = 0

    def embed(self, text: str) -> list[float]:
        vector = self.service.embed_one(text, model=self.model)
        if self.dim <= 0 and vector:
            self.dim = len(vector)
        return vector

    def embed_batch(self, texts: list[str]) -> list[list[float]]:
        vectors = self.service.embed(texts, model=self.model)
        if self.dim <= 0 and vectors:
            self.dim = len(vectors[0])
        return vectors

    def get_dim(self) -> int:
        return self.dim


def list_embedding_models() -> dict[str, dict[str, Any]]:
    """Return available embedding methods and metadata."""
    return {
        "hash": {
            "display_name": "Hash Embedding",
            "description": "Deterministic local hash embedding",
            "requires_api_key": False,
            "requires_download": False,
            "default_dimension": 384,
            "examples": ["hash"],
        },
        "mockembedder": {
            "display_name": "Mock Embedder",
            "description": "Testing-only deterministic embedder",
            "requires_api_key": False,
            "requires_download": False,
            "default_dimension": 128,
            "examples": ["mockembedder"],
        },
        "openai": {
            "display_name": "OpenAI-Compatible Endpoint",
            "description": "HTTP /v1/embeddings compatible endpoint",
            "requires_api_key": False,
            "requires_download": False,
            "default_dimension": "dynamic",
            "examples": ["BAAI/bge-m3"],
        },
        "sagellm": {
            "display_name": "SageLLM Embedding Service",
            "description": "Embedding via SageLLM server endpoint",
            "requires_api_key": False,
            "requires_download": False,
            "default_dimension": "dynamic",
            "examples": ["BAAI/bge-m3"],
        },
    }


def check_model_availability(method: str, **_: Any) -> dict[str, str]:
    """Check whether an embedding method is available in current runtime."""
    methods = list_embedding_models()
    if method not in methods:
        return {
            "status": "unavailable",
            "message": f"Unknown embedding method: {method}",
            "action": "Use 'sage embedding list' to inspect supported methods",
        }
    return {
        "status": "available",
        "message": f"Embedding method '{method}' is available",
        "action": "Ready",
    }


def get_embedding_model(method: str, **kwargs: Any) -> Any:
    """Create an embedding model instance with legacy-compatible interface."""
    method = method.lower().strip()

    if method == "hash":
        dim = int(kwargs.get("dim") or kwargs.get("dimensions") or 384)
        return _HashEmbedder(dim=max(64, dim))

    if method == "mockembedder":
        dim = int(kwargs.get("fixed_dim") or kwargs.get("dim") or 128)
        return _MockEmbedder(dim=max(8, dim))

    if method in {"openai", "sagellm"}:
        base_url = str(kwargs.get("base_url") or "http://127.0.0.1:8890")
        model = kwargs.get("model")
        timeout_s = float(kwargs.get("timeout_s") or 30.0)
        normalize = bool(kwargs.get("normalize", True))
        service = EmbeddingService.from_endpoint(
            base_url=base_url,
            model=str(model) if model else "sentence-transformers/all-MiniLM-L6-v2",
            timeout_s=timeout_s,
            normalize=normalize,
        )
        return _EndpointEmbedder(service=service, model=str(model) if model else None)

    raise ValueError(f"Unsupported embedding method in sagellm migration phase: {method}")


class EmbeddingFactory:
    """Legacy-compatible factory interface."""

    @staticmethod
    def create(method: str, **kwargs: Any) -> Any:
        return get_embedding_model(method, **kwargs)

    @staticmethod
    def list_models() -> dict[str, dict[str, Any]]:
        return list_embedding_models()

    @staticmethod
    def check_availability(method: str, **kwargs: Any) -> dict[str, str]:
        return check_model_availability(method, **kwargs)


class EmbeddingRegistry:
    """Legacy-compatible registry subset."""

    @staticmethod
    def list_methods() -> list[str]:
        return list(list_embedding_models().keys())
