import numpy as np
from skfem import Mesh


def get_element_midpoints(mesh: Mesh, transpose: bool = True) -> np.ndarray:
    midpoints = np.mean(mesh.p[:, mesh.t], axis=1)
    return midpoints.T if transpose else midpoints

# 算三个顶点的mean/std/...
def get_aggregation_per_element(
    solution: np.ndarray,
    element_indices: np.ndarray,
    aggregation_function_str: str = "mean",
) -> np.ndarray:
    vals = solution[element_indices]
    if aggregation_function_str == "mean":
        return vals.mean(axis=1)
    elif aggregation_function_str == "std":
        return vals.std(axis=1)
    elif aggregation_function_str == "min":
        return vals.min(axis=1)
    elif aggregation_function_str == "max":
        return vals.max(axis=1)
    elif aggregation_function_str == "median":
        return np.median(vals, axis=1)
    raise ValueError(f"Unknown aggregation function: {aggregation_function_str}")


# 计算三角形面积
def get_triangle_areas_from_indices(
    positions: np.ndarray, triangle_indices: np.ndarray
) -> np.ndarray:
    i0, i1, i2 = triangle_indices[:, 0], triangle_indices[:, 1], triangle_indices[:, 2]
    return np.abs(0.5 * (
        (positions[i1, 0] - positions[i0, 0]) * (positions[i2, 1] - positions[i0, 1])
        - (positions[i2, 0] - positions[i0, 0]) * (positions[i1, 1] - positions[i0, 1])
    ))


# penalty:\alpha的采样方式
def sample_in_range(max_value: float, min_value: float, sampling_type: str) -> float:
    if sampling_type == "uniform":
        return np.random.uniform(min_value, max_value)
    elif sampling_type == "loguniform":
        return np.exp(np.random.uniform(np.log(min_value), np.log(max_value)))
    raise ValueError(f"Unknown sampling type: {sampling_type}")


def construct_sizing_field_1d(x: np.ndarray, eps: float = 1e-4) -> np.ndarray:
    """Softplus 激活 → 目标网格面积 (numpy 版)。"""
    def _softplus(x):
        return np.log1p(np.exp(np.clip(x, -50, 50)))
    x = np.atleast_1d(np.asarray(x, dtype=np.float64))
    return _softplus(x) + eps
