import pandas as pd
import numpy as np
import re
from typing import Tuple

def curve_score(
    value: float, 
    spec_range: Tuple[float, float], 
    weight: float,
    min_score: float = 0.0,
    base_curvature: float = 2.0,
    narrow_range_coeff: float = 5.0
) -> float:
    lower, upper = spec_range

    if lower <= value <= upper:
        return 1.0
    
    # 计算规格宽度和边界
    if lower == -np.inf and upper == np.inf:
        return 1.0
    elif lower == -np.inf:
        spec_width = abs(upper) * 2 if upper != 0 else 1
        bound = upper
    elif upper == np.inf:
        spec_width = abs(lower) * 2 if lower != 0 else 1
        bound = lower
    else:
        spec_width = upper - lower
        bound = lower if value < lower else upper

    # 标准化距离
    distance = abs(value - bound)
    if spec_width == 0:
        distance_ratio = distance / (abs(bound) + 1e-6)
    else:
        distance_ratio = distance / spec_width

    # 动态曲率(基础曲率×权重×窄化系数)
    if spec_width > 0:
        narrow_coeff = 1 + narrow_range_coeff / (spec_width + 1)
    else:
        narrow_coeff = 1 + narrow_range_coeff
    dynamic_curvature = base_curvature * weight * narrow_coeff

    # 严重偏离额外惩罚
    if distance_ratio > 0.5:
        distance_ratio = distance_ratio ** 1.5

    return max(min_score, np.exp(-dynamic_curvature * distance_ratio))

def dynamic_filter_sort(predictedDF, target_spec, weights):
    mask = pd.Series(True, index=predictedDF.index)
    filtered_df = predictedDF[mask].copy()
    score = pd.Series(0.0, index=filtered_df.index)

    for col, cond in target_spec.items():
        col_values = filtered_df[col].astype(float)
        weight = weights.get(col, 1.0)

        # 给窄范围spec加隐性权重(可选,根据需求开启)
        if '-' in cond:
            low, high = map(float, re.fullmatch(r'^(-?\d+\.?\d*)-(-?\d+\.?\d*)$', cond).groups())
            spec_width = high - low
            if spec_width < 10:  # 范围宽度<10判定为窄范围
                weight *= 1.2  # 隐性权重系数

        # 条件处理
        if '-' in cond:
            spec = (low, high)
            normalized = col_values.apply(lambda x: curve_score(x, spec, weight=weight))
            score += normalized * weight
        elif cond.startswith('lt('):
            ceiling = float(cond[3:-1])
            spec = (-np.inf, ceiling)
            normalized = col_values.apply(lambda x: curve_score(x, spec, weight=weight))
            score += normalized * weight
        elif cond.startswith('gt('):
            floor = float(cond[3:-1])
            spec = (floor, np.inf)
            normalized = col_values.apply(lambda x: curve_score(x, spec, weight=weight))
            score += normalized * weight
        else:
            try:
                target_val = float(cond)
            except ValueError:
                target_val = cond
            spec = (target_val, target_val)
            normalized = col_values.apply(lambda x: curve_score(x, spec, weight=weight))
            score += normalized * weight

    filtered_df['score#'] = round(score, 3)
    return filtered_df.sort_values('score#', ascending=False)

# 业务代码(无需修改,直接使用)
data_df = pd.DataFrame(
    np.array(result['specMatrix'])[recipe_index,:].reshape(1,-1),
    columns=result['maxMatrix'].keys()
)
target_spec = {
    'Depth': '1100-1300', 
    'SOCremain': '0-500', 
    'SiNSWA': '86-89', 
    'TCD': '21-22',
    'doubleslope': '0-1', 
    'maskremain': '2201.8-2833.7'
}
weights = {
    'Depth': 3, 
    'SOCremain': 1, 
    'SiNSWA': 1, 
    'TCD': 3,  # 可根据需要调整为3.5
    'doubleslope': 2, 
    'maskremain': 1
}

data_df = (-dynamic_filter_sort(data_df, target_spec, weights)['score#'].values[:]).tolist()