
export interface ModelPricingFloorTableConfig {
    field: string | null;
    mapping: Record<string, unknown>;
}

export interface ModelPricingAddonConfig {
    field_key: string | null;
    operator: string;
    condition_value: unknown;
    condition_values: unknown[];
    price: number | null;
    unit_field: string | null;
}

export interface ModelPricingMatrixRowConfig {
    price: number | null;
    price_cent: number | null;
    rate: number | null;
    price_per_unit: number | null;
    unit_price: number | null;
    raw: Record<string, unknown>;
}

export interface ModelPricingConfig {
    mode: string | null;
    price_type: string | null;
    billing_mode: string | null;
    price: number | null;
    price_per_k: number | null;
    price_cent: number | null;
    price_per_k_cent: number | null;
    field: string | null;
    unit_field: string | null;
    unit_scale: number | null;
    round_digits: number | null;
    dimensions: string[];
    rate_dimensions: string[];
    matrix: ModelPricingMatrixRowConfig[];
    conditional_addons: ModelPricingAddonConfig[];
    floor_table: ModelPricingFloorTableConfig | null;
    submit_warning_threshold: number | null;
    raw: Record<string, unknown>;
}

export interface ModelDefinition {
    id: string;
    name: string;
    pricing_config: ModelPricingConfig | null;
}

// ============================================================
// 工具函数
// ============================================================

/** 对应 Python: _as_float(value) -> Optional[float] */
function asFloat(value: unknown): number | null {
    if (value === null || value === undefined) return null;
    if (typeof value === "number" && !Number.isNaN(value)) return value;
    if (typeof value === "string") {
        const text = value.trim();
        if (!text) return null;
        const parsed = Number(text);
        return Number.isNaN(parsed) ? null : parsed;
    }
    return null;
}

/** 对应 Python: _to_int(value, *, default=0) -> int */
function toInt(value: unknown, defaultValue: number = 0): number {
    if (value === null || value === undefined) return defaultValue;
    if (typeof value === "boolean") return value ? 1 : 0;
    if (typeof value === "number") return Math.trunc(value);
    if (typeof value === "string") {
        const text = value.trim();
        if (!text) return defaultValue;
        const parsed = parseInt(text, 10);
        return Number.isNaN(parsed) ? defaultValue : parsed;
    }
    return defaultValue;
}

/** 对应 Python: _cent_to_yuan(value) -> float */
function centToYuan(value: unknown): number {
    return toInt(value, 0) / 100.0;
}

/** 对应 Python: _lookup_mapping_value(mapping, key, default="") -> object */
function lookupMappingValue(
    mapping: Record<string, unknown> | null | undefined,
    key: unknown,
    defaultValue: unknown = "",
): unknown {
    const keyStr = String(key);
    if (mapping == null) return defaultValue;
    if (keyStr in mapping) return mapping[keyStr];
    return defaultValue;
}

/** 对应 Python: _match_dimensions(entry, dimensions, inputs) -> bool */
function matchDimensions(
    entry: Record<string, unknown> | null | undefined,
    dimensions: string[],
    inputs: Record<string, unknown>,
): boolean {
    if (entry == null) return false;
    for (const dim of dimensions) {
        const entryValue = lookupMappingValue(entry, dim, null);
        if (entryValue === null || entryValue === undefined) continue;
        const inputVal = String(lookupMappingValue(inputs, dim, "")).trim().toLowerCase();
        const entryVal = String(entryValue).trim().toLowerCase();
        if (inputVal !== entryVal) return false;
    }
    return true;
}

/**
 * 从 matrix 行提取维度数据。
 *
 * API 返回的 matrix 行中，维度字段（如 resolution、quality）在顶层，
 * 而非嵌套在 raw 子对象内。本函数合并 raw（如果存在）和行自身字段，
 * 兼容两种数据格式，确保 matchDimensions 能正确匹配。
 */
function matrixRowData(row: ModelPricingMatrixRowConfig): Record<string, unknown> {
    return { ...(row.raw ?? {}), ...row as unknown as Record<string, unknown> };
}

// ============================================================
// 金额格式化函数
// ============================================================

/**
 * 将元数值格式化为显示字符串，保留两位小数，去除尾部无意义的零和小数点。
 * 对应 workbench.py / billing_dialog.py: _format_yuan(value: float) -> str
 */
export function formatYuan(value: number): string {
    const rounded = Math.round(value * 100) / 100;
    // .toFixed(2) → 去除尾部零 → 去除尾部小数点
    return rounded.toFixed(2).replace(/\.?0+$/, "");
}

/**
 * 将分(cent)转换为元并格式化。
 * 对应 workbench.py / billing_dialog.py / account_dialog.py: _format_yuan_from_cent(cent: int) -> str
 */
export function formatYuanFromCent(cent: number): string {
    return formatYuan(cent / 100.0);
}

/**
 * 格式化金额（分→元），带符号和￥前缀。
 * 对应 task_table.py: _format_money_cent(value: object) -> str
 */
export function formatMoneyCent(value: unknown): string {
    if (value === null || value === undefined) return "-";
    if (typeof value === "boolean") return String(value);

    let cent: number;
    if (typeof value === "number") {
        cent = Math.trunc(value);
    } else if (typeof value === "string") {
        const parsed = parseInt(value, 10);
        if (Number.isNaN(parsed)) return value;
        cent = parsed;
    } else {
        return String(value);
    }

    const sign = cent < 0 ? "-" : "";
    const centAbs = Math.abs(cent);
    const yuan = centAbs / 100.0;
    const text = yuan.toFixed(2).replace(/\.?0+$/, "");
    return `${sign}￥${text}`;
}

/**
 * 格式化分→元，带符号和￥前缀。
 * 对应 admin_console_dialog.py: _format_cent(cent: int) -> str
 */
export function formatCent(cent: number): string {
    const sign = cent < 0 ? "-" : "";
    const valueAbs = Math.abs(Math.trunc(cent));
    const yuan = valueAbs / 100.0;
    const text = yuan.toFixed(2).replace(/\.?0+$/, "");
    return `${sign}￥${text}`;
}

// ============================================================
// 服务端计价逻辑
// ============================================================

/** 对应 Python: _calculate_server_simple(pricing, inputs) -> float */
function calculateServerSimple(
    pricing: ModelPricingConfig,
    inputs: Record<string, unknown>,
): number {
    const priceCent = pricing.price_cent ?? 0;
    const unitField = (pricing.unit_field ?? "").trim();
    if (!unitField) {
        return priceCent / 100.0;
    }
    const amount = asFloat(inputs[unitField]);
    const amountValue = amount === null ? 1.0 : amount;
    // (priceCent * amountValue) / 100 * 100 在 IEEE 754 下可能产生
    // 浮点累积误差（例如 0.03*100→2.999...），直接 round 分子避免
    return Math.round(priceCent * amountValue) / 100;
}

/** 对应 Python: _calculate_server_multi_dimension(pricing, inputs) -> Optional[float] */
function calculateServerMultiDimension(
    pricing: ModelPricingConfig,
    inputs: Record<string, unknown>,
): number | null {
    const { dimensions, matrix } = pricing;
    if (!matrix || matrix.length === 0) return null;

    for (const row of matrix) {
        if (matchDimensions(matrixRowData(row), dimensions, inputs)) {
            return centToYuan(row.price_cent);
        }
    }

    const firstRow = matrix[0];
    if (firstRow.price_cent !== null && firstRow.price_cent !== undefined) {
        return centToYuan(firstRow.price_cent);
    }
    return null;
}

/** 对应 Python: _calculate_server_billing_adapter(pricing, inputs) -> Optional[float] */
function calculateServerBillingAdapter(
    pricing: ModelPricingConfig,
    inputs: Record<string, unknown>,
): number | null {
    const billingMode = (pricing.billing_mode ?? "rate").trim().toLowerCase();
    let baseCostCent = 0;

    if (billingMode === "per_k_chars") {
        const field = (pricing.field ?? "prompt").trim() || "prompt";
        const text = String(inputs[field] ?? "");
        const pricePerKCent = pricing.price_per_k_cent ?? 0;
        baseCostCent = Math.floor((text.length + 999) / 1000) * pricePerKCent;
    } else {
        const matrix = pricing.matrix;
        if (!matrix || matrix.length === 0) return null;

        const dimensions = pricing.dimensions;
        const unitField = (pricing.unit_field ?? "duration").trim() || "duration";
        const unitsRaw = asFloat(inputs[unitField]);
        let units = unitsRaw === null ? 1.0 : unitsRaw;

        // 底表修正
        const floorTable = pricing.floor_table;
        if (floorTable) {
            const floorField = (floorTable.field ?? "").trim();
            if (floorField === unitField) {
                const floorValue = asFloat(floorTable.mapping[String(Math.trunc(units))]);
                if (floorValue !== null && units < floorValue) {
                    units = floorValue;
                }
            }
        }

        let rate: number | null = null;
        for (const row of matrix) {
            if (matchDimensions(matrixRowData(row), dimensions, inputs)) {
                rate = row.rate;
                break;
            }
        }
        if (rate === null) {
            rate = matrix[0].rate;
        }
        if (rate === null || rate === undefined) return null;

        baseCostCent = Math.round(rate * units * 100);
    }

    // 条件附加费
    for (const addon of pricing.conditional_addons ?? []) {
        const fieldKey = (addon.field_key ?? "").trim();
        const operator = addon.operator;
        let matched = false;

        if (operator === "PRESENT") {
            matched = Boolean(inputs[fieldKey]);
        } else if (operator === "EQ") {
            matched = String(inputs[fieldKey] ?? "") === String(addon.condition_value ?? "");
        } else if (operator === "IN") {
            const conditionValues = (addon.condition_values ?? []).map((v) => String(v));
            matched = conditionValues.includes(String(inputs[fieldKey] ?? ""));
        }

        if (!matched) continue;

        const addonPrice = addon.price;
        if (addonPrice === null || addonPrice === undefined) continue;

        const addonUnitField = String(
            addon.unit_field ?? pricing.unit_field ?? "duration",
        ).trim() || "duration";
        const addonUnitsRaw = asFloat(inputs[addonUnitField]);
        const addonUnits = addonUnitsRaw === null ? 1.0 : addonUnitsRaw;

        baseCostCent += Math.round(addonPrice * addonUnits * 100);
    }

    return baseCostCent / 100.0;
}

// ============================================================
// 主计价入口
// ============================================================

/**
 * 根据模型定义和输入参数，动态计算消耗金额（单位：元）。
 * 对应 Python: calculate_cost(model: ModelDefinition, inputs: Mapping) -> Optional[float]
 */
export function calculateCost(
    model: ModelDefinition,
    inputs: Record<string, unknown>,
): number | null {
    const pricing = model.pricing_config;
    if (!pricing) return null;

    // ── 服务端定价 (price_type 存在且 mode 不存在) ──
    if (pricing.price_type && !pricing.mode) {
        const priceType = (pricing.price_type ?? "SIMPLE").trim().toUpperCase();
        switch (priceType) {
            case "SIMPLE":
                return calculateServerSimple(pricing, inputs);
            case "MULTI_DIMENSION":
                return calculateServerMultiDimension(pricing, inputs);
            case "BILLING_ADAPTER":
                return calculateServerBillingAdapter(pricing, inputs);
            default:
                return null;
        }
    }

    // ── 客户端定价 ──
    const mode = pricing.mode;

    if (mode === "fixed") {
        if (pricing.price !== null && pricing.price !== undefined) {
            return pricing.price;
        }
        return Number(pricing.raw?.price ?? 0);
    }

    if (mode === "per_k_chars") {
        const fieldId = String(pricing.field ?? "text");
        const rawText = inputs[fieldId] ?? "";
        const text = rawText !== null && rawText !== undefined ? String(rawText) : "";
        const pricePerK =
            pricing.price_per_k ?? Number(pricing.raw?.price_per_k ?? 0);
        return (text.length / 1000) * pricePerK;
    }

    if (mode === "rate_matrix") {
        const unitField = String(pricing.unit_field ?? "duration");

        const unitRaw = inputs[unitField];
        const unitValue = asFloat(unitRaw);
        if (unitValue === null) return null;

        const { rate_dimensions, matrix } = pricing;
        if (!rate_dimensions || rate_dimensions.length === 0 || !matrix || matrix.length === 0) {
            return null;
        }

        for (const entry of matrix) {
            if (matchDimensions(matrixRowData(entry), rate_dimensions, inputs)) {
                let rate = entry.rate;
                if (rate === null || rate === undefined) rate = entry.price_per_unit;
                if (rate === null || rate === undefined) rate = entry.unit_price;
                if (rate === null || rate === undefined) rate = 0.0;

                const rawRound = pricing.round_digits ?? pricing.raw?.round ?? 2;
                const roundDigits =
                    typeof rawRound === "number" || (typeof rawRound === "string" && String(rawRound).trim())
                        ? Number(rawRound)
                        : 2;
                return (
                    Math.round(unitValue * rate * Math.pow(10, roundDigits)) /
                    Math.pow(10, roundDigits)
                );
            }
        }
        return null;
    }

    if (mode === "matrix") {
        const { dimensions, matrix } = pricing;
        // 与 MULTI_DIMENSION 对齐：dimensions 为空时 matchDimensions 自动全匹配
        if (!matrix || matrix.length === 0) {
            return null;
        }

        for (const entry of matrix) {
            if (matchDimensions(matrixRowData(entry), dimensions, inputs)) {
                // price_cent 优先：Python 端矩阵定价统一走 cent 分度值，
                // entry.price 可能为衍生/展示值，price_cent 才是计价基准
                if (entry.price_cent !== null && entry.price_cent !== undefined) {
                    return entry.price_cent / 100;
                }
                if (entry.price !== null && entry.price !== undefined) {
                    return entry.price;
                }
                return Number(entry.raw?.price ?? 0);
            }
        }
        return null;
    }

    return null;
}

// ============================================================
// 定价依赖字段收集
// ============================================================

/**
 * 收集定价计算所依赖的输入字段名集合。
 * 对应 Python: collect_pricing_dependent_fields(model: ModelDefinition) -> set[str]
 */
export function collectPricingDependentFields(model: ModelDefinition): Set<string> {
    const pricing = model.pricing_config;
    if (!pricing) return new Set();

    const fields = new Set<string>();
    const priceType = (pricing.price_type ?? "").trim().toUpperCase();
    const mode = (pricing.mode ?? "").trim().toLowerCase();
    const billingMode = (pricing.billing_mode ?? "").trim().toLowerCase();

    if (priceType === "SIMPLE") {
        const unitField = (pricing.unit_field ?? "").trim();
        if (unitField) fields.add(unitField);
    } else if (priceType === "MULTI_DIMENSION") {
        for (const dim of pricing.dimensions) {
            const dimText = String(dim).trim();
            if (dimText) fields.add(dimText);
        }
    } else if (priceType === "BILLING_ADAPTER") {
        if (billingMode === "per_k_chars") {
            const field = String(pricing.field ?? "prompt").trim() || "prompt";
            fields.add(field);
        } else {
            const unitField = String(pricing.unit_field ?? "duration").trim() || "duration";
            fields.add(unitField);

            const floorTable = pricing.floor_table;
            if (floorTable) {
                const floorField = String(floorTable.field ?? "").trim();
                if (floorField) fields.add(floorField);
            }
            for (const dim of pricing.dimensions) {
                const dimText = String(dim).trim();
                if (dimText) fields.add(dimText);
            }
        }
        for (const addon of pricing.conditional_addons ?? []) {
            const fieldKey = String(addon.field_key ?? "").trim();
            if (fieldKey) fields.add(fieldKey);
            const addonUnitField = String(
                addon.unit_field ?? pricing.unit_field ?? "duration",
            ).trim();
            if (addonUnitField) fields.add(addonUnitField);
        }
    } else if (mode === "per_k_chars") {
        const field = String(pricing.field ?? "text").trim() || "text";
        fields.add(field);
    } else if (mode === "rate_matrix") {
        const unitField = String(pricing.unit_field ?? "duration").trim() || "duration";
        fields.add(unitField);
        for (const dim of pricing.rate_dimensions) {
            const dimText = String(dim).trim();
            if (dimText) fields.add(dimText);
        }
    } else if (mode === "matrix") {
        for (const dim of pricing.dimensions) {
            const dimText = String(dim).trim();
            if (dimText) fields.add(dimText);
        }
    }

    return fields;
}
