defmodule TradeMachine.GMGradeV2.Pillars.AssetManagement.DraftCapitalValue do @moduledoc """ Scores the post-scenario draft inventory against the frozen 30-team DAV total. `DAV.Inventory` is the shared Phase 7 implementation of AVC's controlled-claim rules: it resolves part-level ownership, excludes out-of-window and duplicate claims, values swaps as inventory holdings, and preserves incremental swap DAV separately for the expanded view. """ alias TradeMachine.GMGradeV2.Benchmark alias TradeMachine.GMGradeV2.DAV.Inventory alias TradeMachine.GMGradeV2.Percentile alias TradeMachine.GMGradeV2.Pillars.AssetManagement.JSONSafe alias TradeMachine.GMGradeV2.Result.MetricResult @doc "Builds and scores one team's final seven-draft inventory." @spec score(binary(), Inventory.graph(), map(), Benchmark.t()) :: MetricResult.t() def score(team_id, graph, dav_context, %Benchmark{} = benchmark) do team_id |> Inventory.value(graph, dav_context) |> score_inventory(benchmark) end @doc "Scores an already-built Phase 7 inventory against the frozen benchmark." @spec score_inventory(Inventory.t(), Benchmark.t()) :: MetricResult.t() def score_inventory(inventory, %Benchmark{} = benchmark) do benchmark_values = benchmark_values(benchmark, "total") %MetricResult{ key: :draft_capital_value, version: benchmark.version, score: Percentile.score(inventory.total, benchmark_values), inputs: %{ total_dav: inventory.total, asset_count: inventory.asset_count, window: %{first_year: inventory.window.first, last_year: inventory.window.last}, benchmark: benchmark_values }, supporting: %{ first_round_dav: inventory.first_round, second_round_dav: inventory.second_round, swap_dav: inventory.swap_gain, by_year: breakdown(inventory.assets, & &1.year), by_origin_team: breakdown(inventory.assets, &(&1.original_team_id || :swap_pool)), assets: JSONSafe.value(inventory.assets) }, explanation: "Draft Capital Value percentiles #{inventory.total} total DAV across " <> "#{inventory.asset_count} controlled assets against the frozen league inventory." } end defp benchmark_values(benchmark, metric) do benchmark |> Benchmark.section(:dav) |> Map.fetch!("metrics") |> Map.fetch!(metric) end defp breakdown(assets, key_fun) do assets |> Enum.group_by(key_fun) |> Enum.map(fn {key, grouped} -> {key, Enum.reduce(grouped, 0.0, &(&2 + &1.inventory_dav))} end) |> Map.new() end end