defmodule BlockScoutWeb.CBSPoolView do
  @moduledoc """
  Blockscout 定制模块：CBS(CouponBackedSecurity)池详情页 (P1)
  - 资产证券化池的底层券
  - 份额持有人
  - 收益分配记录
  """

  alias Explorer.SmartContract.Reader

  @cbs_abi [
    %{
      "name" => "getPoolInfo",
      "type" => "function",
      "stateMutability" => "view",
      "inputs" => [%{"name" => "poolId", "type" => "uint256"}],
      "outputs" => [
        %{"name" => "totalShares", "type" => "uint256"},
        %{"name" => "totalUnderlying", "type" => "uint256"},
        %{"name" => "createdAt", "type" => "uint256"},
        %{"name" => "active", "type" => "bool"}
      ]
    },
    %{
      "name" => "getUnderlyingCoupons",
      "type" => "function",
      "stateMutability" => "view",
      "inputs" => [%{"name" => "poolId", "type" => "uint256"}],
      "outputs" => [%{"name" => "", "type" => "uint256[]"}]
    },
    %{
      "name" => "getShareBalance",
      "type" => "function",
      "stateMutability" => "view",
      "inputs" => [
        %{"name" => "poolId", "type" => "uint256"},
        %{"name" => "holder", "type" => "address"}
      ],
      "outputs" => [%{"name" => "", "type" => "uint256"}]
    }
  ]

  # RevenueDistributed 事件
  @revenue_distributed_topic "0x" <>
    Base.encode16(:crypto.hash(:keccak256, "RevenueDistributed(uint256,uint256,uint256)"), case: :lower)

  @doc "获取 CBS 池完整详情"
  def get_pool_detail(pool_id, cbs_contract) do
    with {:ok, info} <- get_pool_info(pool_id, cbs_contract),
         {:ok, coupons} <- get_underlying_coupons(pool_id, cbs_contract) do
      %{
        pool_id: pool_id,
        total_shares: info.total_shares,
        total_underlying: info.total_underlying,
        created_at: DateTime.from_unix!(info.created_at),
        active: info.active,
        underlying_coupons: coupons,
        coupon_count: length(coupons),
        distributions: get_distribution_history(pool_id, cbs_contract)
      }
    else
      {:error, reason} -> {:error, reason}
    end
  end

  @doc "获取池的收益分配历史"
  def get_distribution_history(pool_id, _cbs_contract) do
    # 查询 RevenueDistributed 事件日志
    # 实际实现需要查询 Explorer.Chain.Log
    []
    |> Enum.map(fn log ->
      case log.first_topic do
        @revenue_distributed_topic ->
          %{
            pool_id: decode_uint256(log.second_topic),
            amount: decode_uint256_from_data(log.data, 0),
            timestamp: decode_uint256_from_data(log.data, 1),
            block_number: log.block_number,
            tx_hash: log.transaction_hash
          }

        _ ->
          nil
      end
    end)
    |> Enum.filter(&(&1 != nil))
    |> Enum.filter(&(&1.pool_id == pool_id))
  end

  @doc "解析 RevenueDistributed 事件"
  def parse_distribution_event(log) do
    case log.first_topic do
      @revenue_distributed_topic ->
        %{
          pool_id: decode_uint256(log.second_topic),
          amount: decode_uint256_from_data(log.data, 0),
          share_count: decode_uint256_from_data(log.data, 1)
        }

      _ ->
        nil
    end
  end

  # ── 私有函数 ──

  defp get_pool_info(pool_id, contract) do
    case Reader.query_contract(contract, @cbs_abi, %{"getPoolInfo" => [pool_id]}) do
      %{"getPoolInfo" => {:ok, [total_shares, total_underlying, created_at, active]}} ->
        {:ok,
         %{
           total_shares: total_shares,
           total_underlying: total_underlying,
           created_at: created_at,
           active: active
         }}

      _ ->
        {:error, :contract_call_failed}
    end
  end

  defp get_underlying_coupons(pool_id, contract) do
    case Reader.query_contract(contract, @cbs_abi, %{"getUnderlyingCoupons" => [pool_id]}) do
      %{"getUnderlyingCoupons" => {:ok, [coupon_ids]}} -> {:ok, coupon_ids}
      _ -> {:error, :contract_call_failed}
    end
  end

  defp decode_uint256(nil), do: 0
  defp decode_uint256("0x" <> hex), do: String.to_integer(hex, 16)

  defp decode_uint256_from_data(data, offset) do
    data
    |> String.slice(2 + offset * 64, 64)
    |> String.to_integer(16)
  end
end
