<?php
require_once __DIR__ . "/_bootstrap.php";

function norm_key(string $k): string {
    $k = strtolower(trim($k));
    $k = preg_replace('/[^a-z0-9]+/', '_', $k);
    return trim($k, '_');
}

function as_float($v): float {
    if (is_numeric($v)) return (float)$v;
    $s = trim((string)$v);
    if ($s === "") return 0.0;
    // remove % and commas
    $s = str_replace([",", "%"], ["", ""], $s);
    return is_numeric($s) ? (float)$s : 0.0;
}

try {
    $pdo = fxh_optimizer_pdo();
    fxh_optimizer_require_license($pdo);

    $j = fxh_json_input();
    $objective = (string)($j["objective"] ?? "");
    $rows = $j["rows"] ?? null;

    if (!$objective) fxh_send(422, ["error"=>"Missing objective"]);
    if (!is_array($rows) || count($rows) < 1) fxh_send(422, ["error"=>"Missing rows"]);

    // Detect metric columns by fuzzy matching
    $metricMap = [
        "net_profit"   => ["net profit","netprofit","profit","total profit"],
        "profit_factor"=> ["profit factor","pf"],
        "max_drawdown" => ["max drawdown","drawdown","max dd","dd"],
        "win_rate"     => ["win rate","winrate","win %","win%","winning percentage"]
    ];

    $best = [];
    $i = 0;

    foreach ($rows as $r) {
        if (!is_array($r)) continue;
        $i++;

        // Build normalized header map for this row
        $norm = [];
        foreach ($r as $k => $v) {
            $norm[norm_key((string)$k)] = $v;
        }

        // find metric values
        $netProfit = null; $pf = null; $dd = null; $wr = null;

        foreach ($metricMap["net_profit"] as $alias) {
            $nk = norm_key($alias);
            if (array_key_exists($nk, $norm)) { $netProfit = as_float($norm[$nk]); break; }
        }
        foreach ($metricMap["profit_factor"] as $alias) {
            $nk = norm_key($alias);
            if (array_key_exists($nk, $norm)) { $pf = as_float($norm[$nk]); break; }
        }
        foreach ($metricMap["max_drawdown"] as $alias) {
            $nk = norm_key($alias);
            if (array_key_exists($nk, $norm)) { $dd = as_float($norm[$nk]); break; }
        }
        foreach ($metricMap["win_rate"] as $alias) {
            $nk = norm_key($alias);
            if (array_key_exists($nk, $norm)) { $wr = as_float($norm[$nk]); break; }
        }

        // Score
        $score = 0.0;
        switch ($objective) {
            case "net_profit":
                $score = (float)($netProfit ?? 0.0);
                break;
            case "profit_factor":
                $score = (float)($pf ?? 0.0);
                break;
            case "win_rate":
                $score = (float)($wr ?? 0.0);
                break;
            case "max_drawdown":
                // minimize dd: convert to negative score so sorting desc works
                $score = -1.0 * (float)($dd ?? 0.0);
                break;
            default:
                fxh_send(422, ["error"=>"Invalid objective"]);
        }

        // Partition fields into metrics vs parameters
        $metricKeys = ["net_profit","profit_factor","max_drawdown","win_rate"];
        $metricsText = "NP=" . ($netProfit ?? 0) . " | PF=" . ($pf ?? 0) . " | DD=" . ($dd ?? 0) . " | WR=" . ($wr ?? 0);

        // Parameters = everything else except detected metrics (heuristic)
        $params = [];
        foreach ($r as $k => $v) {
            $nk = norm_key((string)$k);
            $isMetric = false;
            foreach ($metricMap as $m => $aliases) {
                foreach ($aliases as $a) {
                    if ($nk === norm_key($a)) { $isMetric = true; break 2; }
                }
            }
            if (!$isMetric) {
                $vv = trim((string)$v);
                if ($vv !== "") $params[] = "{$k}={$vv}";
            }
        }

        $best[] = [
            "score" => $score,
            "metrics" => [
                "net_profit" => (float)($netProfit ?? 0),
                "profit_factor" => (float)($pf ?? 0),
                "max_drawdown" => (float)($dd ?? 0),
                "win_rate" => (float)($wr ?? 0),
            ],
            "metricsText" => $metricsText,
            "params" => $params,
            "paramsText" => implode(" | ", array_slice($params, 0, 20)),
            "raw" => $r
        ];
    }

    // Sort DESC by score
    usort($best, fn($a,$b) => ($b["score"] <=> $a["score"]));

    // Keep top N
    $best = array_slice($best, 0, 200);

    fxh_send(200, [
        "status" => "ok",
        "objective" => $objective,
        "best" => $best
    ]);

} catch (Throwable $e) {
    fxh_send(500, ["error"=>"Server error", "details"=>$e->getMessage()]);
}
