"""Type stubs for rankops Python bindings (PyPI package: rankops)."""

from typing import List, Tuple, Optional, Literal

RankedList = List[Tuple[str, float]]
MultiRankedLists = List[RankedList]
NormalizationType = Literal["zscore", "minmax", "sum", "rank", "none"]

# Configuration Classes

class RrfConfig:
    k: int
    def __init__(self, k: int = 60) -> None: ...
    def with_k(self, k: int) -> "RrfConfig": ...

class FusionConfig:
    def __init__(self) -> None: ...
    def with_top_k(self, top_k: int) -> "FusionConfig": ...

class WeightedConfig:
    weight_a: float
    weight_b: float
    def __init__(self, weight_a: float, weight_b: float) -> None: ...
    def with_normalize(self, normalize: bool) -> "WeightedConfig": ...
    def with_top_k(self, top_k: int) -> "WeightedConfig": ...

class StandardizedConfig:
    clip_range: Tuple[float, float]
    def __init__(self, clip_range: Tuple[float, float] = (-3.0, 3.0)) -> None: ...
    def with_top_k(self, top_k: int) -> "StandardizedConfig": ...

class AdditiveMultiTaskConfig:
    weights: Tuple[float, float]
    def __init__(self, weights: Tuple[float, float] = (1.0, 1.0), normalization: str = "minmax") -> None: ...
    def with_normalization(self, normalization: NormalizationType) -> "AdditiveMultiTaskConfig": ...
    def with_top_k(self, top_k: int) -> "AdditiveMultiTaskConfig": ...

# Explainability Classes

class SourceContribution:
    retriever_id: str
    original_rank: Optional[int]
    original_score: Optional[float]
    normalized_score: Optional[float]
    contribution: float

class Explanation:
    sources: List[SourceContribution]
    method: str
    consensus_score: float

class FusedResult:
    id: str
    score: float
    rank: int
    explanation: Explanation

class RetrieverId:
    id: str
    def __init__(self, id: str) -> None: ...

class RetrieverStats:
    top_k_count: int
    avg_contribution: float
    unique_docs: int

class ConsensusReport:
    high_consensus: List[str]
    single_source: List[str]
    rank_disagreement: List[Tuple[str, List[Tuple[str, int]]]]

class ValidationResult:
    is_valid: bool
    errors: List[str]
    warnings: List[str]

# Rank-based Fusion

def rrf(results_a: RankedList, results_b: RankedList, k: int = 60, top_k: Optional[int] = None) -> RankedList: ...
def rrf_multi(lists: MultiRankedLists, k: int = 60, top_k: Optional[int] = None) -> RankedList: ...
def isr(results_a: RankedList, results_b: RankedList, k: int = 1, top_k: Optional[int] = None) -> RankedList: ...
def isr_multi(lists: MultiRankedLists, k: int = 1, top_k: Optional[int] = None) -> RankedList: ...
def borda(results_a: RankedList, results_b: RankedList, top_k: Optional[int] = None) -> RankedList: ...
def borda_multi(lists: MultiRankedLists, top_k: Optional[int] = None) -> RankedList: ...

# Score-based Fusion

def combsum(results_a: RankedList, results_b: RankedList, top_k: Optional[int] = None) -> RankedList: ...
def combsum_multi(lists: MultiRankedLists, top_k: Optional[int] = None) -> RankedList: ...
def combmnz(results_a: RankedList, results_b: RankedList, top_k: Optional[int] = None) -> RankedList: ...
def combmnz_multi(lists: MultiRankedLists, top_k: Optional[int] = None) -> RankedList: ...
def weighted(results_a: RankedList, results_b: RankedList, weight_a: float, weight_b: float, normalize: bool = True, top_k: Optional[int] = None) -> RankedList: ...
def dbsf(results_a: RankedList, results_b: RankedList, top_k: Optional[int] = None) -> RankedList: ...
def dbsf_multi(lists: MultiRankedLists, top_k: Optional[int] = None) -> RankedList: ...
def standardized(results_a: RankedList, results_b: RankedList, clip_range: Tuple[float, float] = (-3.0, 3.0), top_k: Optional[int] = None) -> RankedList: ...
def standardized_multi(lists: MultiRankedLists, clip_range: Tuple[float, float] = (-3.0, 3.0), top_k: Optional[int] = None) -> RankedList: ...
def additive_multi_task(results_a: RankedList, results_b: RankedList, weights: Tuple[float, float] = (1.0, 1.0), normalization: str = "minmax", top_k: Optional[int] = None) -> RankedList: ...

# Explainability

def rrf_explain(lists: MultiRankedLists, retriever_ids: List[str], k: int = 60, top_k: Optional[int] = None) -> List[FusedResult]: ...
def combsum_explain(lists: MultiRankedLists, retriever_ids: List[str], top_k: Optional[int] = None) -> List[FusedResult]: ...
def combmnz_explain(lists: MultiRankedLists, retriever_ids: List[str], top_k: Optional[int] = None) -> List[FusedResult]: ...
def dbsf_explain(lists: MultiRankedLists, retriever_ids: List[str], top_k: Optional[int] = None) -> List[FusedResult]: ...

# Validation

def validate_sorted(results: RankedList) -> ValidationResult: ...
def validate_no_duplicates(results: RankedList) -> ValidationResult: ...
def validate_finite_scores(results: RankedList) -> ValidationResult: ...
def validate_non_negative_scores(results: RankedList) -> ValidationResult: ...
def validate_bounds(results: RankedList, max_results: Optional[int] = None) -> ValidationResult: ...
def validate(results: RankedList, check_non_negative: bool = False, max_results: Optional[int] = None) -> ValidationResult: ...

# Reranking: SIMD vector operations

TokenEmbeddings = List[List[float]]

def dot(a: List[float], b: List[float]) -> float: ...
def cosine(a: List[float], b: List[float]) -> float: ...
def maxsim(query_tokens: TokenEmbeddings, doc_tokens: TokenEmbeddings) -> float: ...
def maxsim_cosine(query_tokens: TokenEmbeddings, doc_tokens: TokenEmbeddings) -> float: ...

# Reranking: ColBERT / MaxSim

def maxsim_rank(query_tokens: TokenEmbeddings, docs: List[Tuple[str, TokenEmbeddings]], top_k: Optional[int] = None) -> RankedList: ...
def maxsim_refine(candidates: RankedList, query_tokens: TokenEmbeddings, docs: List[Tuple[str, TokenEmbeddings]], alpha: float = 0.5, top_k: Optional[int] = None) -> RankedList: ...
def maxsim_alignments(query_tokens: TokenEmbeddings, doc_tokens: TokenEmbeddings) -> List[Tuple[int, int, float]]: ...

# Reranking: Diversity

def mmr(candidates: RankedList, embeddings: List[List[float]], lambda_: float = 0.5, k: int = 10) -> RankedList: ...
def dpp(candidates: RankedList, embeddings: List[List[float]], k: int = 10, alpha: float = 1.0) -> RankedList: ...

# Reranking: Matryoshka

def matryoshka_refine(candidates: RankedList, query: List[float], docs: List[Tuple[str, List[float]]], head_dims: int, alpha: float = 0.5) -> RankedList: ...

# Utilities

def normalize_scores(scores: List[float]) -> List[float]: ...
