import { getExplorerApiBase } from './blockscout'

export interface ExplorerStats {
  total_blocks: number
  total_transactions: number
  total_addresses: number
  latest_block: number | null
  average_block_time_ms: number | null
  average_gas_price_gwei: number | null
  network_utilization_percentage: number | null
  transactions_today: number | null
  freshness: ExplorerFreshnessSnapshot | null
  completeness: ExplorerStatsCompleteness | null
  sampling: ExplorerStatsSampling | null
  diagnostics: ExplorerFreshnessDiagnostics | null
}

export interface ExplorerFreshnessReference {
  block_number: number | null
  timestamp: string | null
  age_seconds: number | null
  hash?: string | null
  distance_from_head?: number | null
  source?: string | null
  confidence?: string | null
  provenance?: string | null
  completeness?: string | null
}

export interface ExplorerFreshnessSnapshot {
  chain_head: ExplorerFreshnessReference
  latest_indexed_block: ExplorerFreshnessReference
  latest_indexed_transaction: ExplorerFreshnessReference
  latest_non_empty_block: ExplorerFreshnessReference
}

export interface ExplorerFreshnessDiagnostics {
  tx_visibility_state?: string | null
  activity_state?: string | null
  explanation?: string | null
  tx_lag_blocks?: number | null
  tx_lag_seconds?: number | null
  recent_block_sample_size?: number | null
  recent_non_empty_blocks?: number | null
  recent_transactions?: number | null
  latest_non_empty_block_from_block_feed?: ExplorerFreshnessReference | null
  source?: string | null
  confidence?: string | null
  provenance?: string | null
  completeness?: string | null
}

export interface ExplorerStatsCompleteness {
  transactions_feed?: string | null
  blocks_feed?: string | null
  gas_metrics?: string | null
  utilization_metrics?: string | null
}

export interface ExplorerStatsSampling {
  stats_generated_at?: string | null
  rpc_probe_at?: string | null
  stats_window_seconds?: number | null
  issues?: Record<string, string> | null
}

export interface ExplorerTransactionTrendPoint {
  date: string
  transaction_count: number
}

export interface ExplorerRecentActivitySnapshot {
  success_rate: number
  failure_rate: number
  average_gas_used: number
  average_fee_wei: number
  contract_creations: number
  token_transfer_txs: number
  contract_calls: number
  contract_creation_share: number
  token_transfer_share: number
  contract_call_share: number
  sample_size: number
}

interface RawExplorerStats {
  total_blocks?: number | string | null
  total_transactions?: number | string | null
  total_addresses?: number | string | null
  latest_block?: number | string | null
  average_block_time?: number | string | null
  gas_prices?: {
    slow?: number | string | null
    average?: number | string | null
    fast?: number | string | null
  } | null
  network_utilization_percentage?: number | string | null
  transactions_today?: number | string | null
  freshness?: {
    chain_head?: RawExplorerFreshnessReference | null
    latest_indexed_block?: RawExplorerFreshnessReference | null
    latest_indexed_transaction?: RawExplorerFreshnessReference | null
    latest_non_empty_block?: RawExplorerFreshnessReference | null
  } | null
  completeness?: ExplorerStatsCompleteness | null
  sampling?: ExplorerStatsSampling | null
  diagnostics?: {
    tx_visibility_state?: string | null
    activity_state?: string | null
    explanation?: string | null
    tx_lag_blocks?: number | string | null
    tx_lag_seconds?: number | string | null
    recent_block_sample_size?: number | string | null
    recent_non_empty_blocks?: number | string | null
    recent_transactions?: number | string | null
    latest_non_empty_block_from_block_feed?: RawExplorerFreshnessReference | null
    source?: string | null
    confidence?: string | null
    provenance?: string | null
    completeness?: string | null
  } | null
}

interface RawExplorerFreshnessReference {
  block_number?: number | string | null
  timestamp?: string | null
  age_seconds?: number | string | null
  hash?: string | null
  distance_from_head?: number | string | null
  source?: string | null
  confidence?: string | null
  provenance?: string | null
  completeness?: string | null
}

function toNumber(value: number | string | null | undefined): number {
  if (typeof value === 'number') return value
  if (typeof value === 'string' && value.trim() !== '') return Number(value)
  return 0
}

function normalizeFreshnessReference(raw?: RawExplorerFreshnessReference | null): ExplorerFreshnessReference {
  return {
    block_number:
      raw?.block_number == null || raw.block_number === '' ? null : toNumber(raw.block_number),
    timestamp: raw?.timestamp || null,
    age_seconds: raw?.age_seconds == null || raw.age_seconds === '' ? null : toNumber(raw.age_seconds),
    hash: raw?.hash || null,
    distance_from_head:
      raw?.distance_from_head == null || raw.distance_from_head === ''
        ? null
        : toNumber(raw.distance_from_head),
    source: raw?.source || null,
    confidence: raw?.confidence || null,
    provenance: raw?.provenance || null,
    completeness: raw?.completeness || null,
  }
}

function normalizeFreshnessSnapshot(raw?: RawExplorerStats['freshness'] | null): ExplorerFreshnessSnapshot | null {
  if (!raw) return null
  return {
    chain_head: normalizeFreshnessReference(raw.chain_head),
    latest_indexed_block: normalizeFreshnessReference(raw.latest_indexed_block),
    latest_indexed_transaction: normalizeFreshnessReference(raw.latest_indexed_transaction),
    latest_non_empty_block: normalizeFreshnessReference(raw.latest_non_empty_block),
  }
}

function normalizeFreshnessDiagnostics(raw?: RawExplorerStats['diagnostics'] | null): ExplorerFreshnessDiagnostics | null {
  if (!raw) return null
  return {
    tx_visibility_state: raw.tx_visibility_state || null,
    activity_state: raw.activity_state || null,
    explanation: raw.explanation || null,
    tx_lag_blocks: raw.tx_lag_blocks == null || raw.tx_lag_blocks === '' ? null : toNumber(raw.tx_lag_blocks),
    tx_lag_seconds: raw.tx_lag_seconds == null || raw.tx_lag_seconds === '' ? null : toNumber(raw.tx_lag_seconds),
    recent_block_sample_size:
      raw.recent_block_sample_size == null || raw.recent_block_sample_size === ''
        ? null
        : toNumber(raw.recent_block_sample_size),
    recent_non_empty_blocks:
      raw.recent_non_empty_blocks == null || raw.recent_non_empty_blocks === ''
        ? null
        : toNumber(raw.recent_non_empty_blocks),
    recent_transactions:
      raw.recent_transactions == null || raw.recent_transactions === ''
        ? null
        : toNumber(raw.recent_transactions),
    latest_non_empty_block_from_block_feed: normalizeFreshnessReference(raw.latest_non_empty_block_from_block_feed),
    source: raw.source || null,
    confidence: raw.confidence || null,
    provenance: raw.provenance || null,
    completeness: raw.completeness || null,
  }
}

export function normalizeExplorerStats(raw: RawExplorerStats): ExplorerStats {
  const latestBlockValue = raw.latest_block
  const averageBlockTimeValue = raw.average_block_time
  const gasPriceAverageValue = raw.gas_prices?.average
  const networkUtilizationValue = raw.network_utilization_percentage
  const transactionsTodayValue = raw.transactions_today

  return {
    total_blocks: toNumber(raw.total_blocks),
    total_transactions: toNumber(raw.total_transactions),
    total_addresses: toNumber(raw.total_addresses),
    latest_block:
      latestBlockValue == null || latestBlockValue === ''
        ? null
        : toNumber(latestBlockValue),
    average_block_time_ms:
      averageBlockTimeValue == null || averageBlockTimeValue === ''
        ? null
        : toNumber(averageBlockTimeValue),
    average_gas_price_gwei:
      gasPriceAverageValue == null || gasPriceAverageValue === ''
        ? null
        : toNumber(gasPriceAverageValue),
    network_utilization_percentage:
      networkUtilizationValue == null || networkUtilizationValue === ''
        ? null
        : toNumber(networkUtilizationValue),
    transactions_today:
      transactionsTodayValue == null || transactionsTodayValue === ''
        ? null
        : toNumber(transactionsTodayValue),
    freshness: normalizeFreshnessSnapshot(raw.freshness),
    completeness: raw.completeness || null,
    sampling: raw.sampling || null,
    diagnostics: normalizeFreshnessDiagnostics(raw.diagnostics),
  }
}

export function normalizeTransactionTrend(raw: {
  chart_data?: Array<{ date?: string | null; transaction_count?: number | string | null }>
}): ExplorerTransactionTrendPoint[] {
  return Array.isArray(raw.chart_data)
    ? raw.chart_data.map((entry) => ({
        date: entry.date || '',
        transaction_count: toNumber(entry.transaction_count),
      }))
    : []
}

export function summarizeRecentTransactions(
  raw: Array<{
    status?: string | null
    transaction_types?: string[] | null
    gas_used?: number | string | null
    fee?: { value?: string | number | null } | string | null
  }>,
): ExplorerRecentActivitySnapshot {
  if (!Array.isArray(raw) || raw.length === 0) {
    return {
      success_rate: 0,
      failure_rate: 0,
      average_gas_used: 0,
      average_fee_wei: 0,
      contract_creations: 0,
      token_transfer_txs: 0,
      contract_calls: 0,
      contract_creation_share: 0,
      token_transfer_share: 0,
      contract_call_share: 0,
      sample_size: 0,
    }
  }

  const sampleSize = raw.length
  const successes = raw.filter((transaction) => ['ok', 'success', '1'].includes((transaction.status || '').toLowerCase())).length
  const totalGasUsed = raw.reduce((sum, transaction) => sum + toNumber(transaction.gas_used), 0)
  const totalFeeWei = raw.reduce((sum, transaction) => {
    const feeValue = typeof transaction.fee === 'string' ? transaction.fee : transaction.fee?.value
    return sum + toNumber(feeValue)
  }, 0)
  const contractCreations = raw.filter((transaction) => transaction.transaction_types?.includes('contract_creation')).length
  const tokenTransferTxs = raw.filter((transaction) => transaction.transaction_types?.includes('token_transfer')).length
  const contractCalls = raw.filter((transaction) => transaction.transaction_types?.includes('contract_call')).length

  return {
    success_rate: successes / sampleSize,
    failure_rate: (sampleSize - successes) / sampleSize,
    average_gas_used: totalGasUsed / sampleSize,
    average_fee_wei: totalFeeWei / sampleSize,
    contract_creations: contractCreations,
    token_transfer_txs: tokenTransferTxs,
    contract_calls: contractCalls,
    contract_creation_share: contractCreations / sampleSize,
    token_transfer_share: tokenTransferTxs / sampleSize,
    contract_call_share: contractCalls / sampleSize,
    sample_size: sampleSize,
  }
}

export const statsApi = {
  get: async (): Promise<ExplorerStats> => {
    const response = await fetch(`${getExplorerApiBase()}/api/v2/stats`)
    if (!response.ok) {
      throw new Error(`HTTP ${response.status}`)
    }
    const json = (await response.json()) as RawExplorerStats
    return normalizeExplorerStats(json)
  },
  getTransactionTrend: async (): Promise<ExplorerTransactionTrendPoint[]> => {
    const response = await fetch(`${getExplorerApiBase()}/api/v2/stats/charts/transactions`)
    if (!response.ok) {
      throw new Error(`HTTP ${response.status}`)
    }
    const json = (await response.json()) as { chart_data?: Array<{ date?: string | null; transaction_count?: number | string | null }> }
    return normalizeTransactionTrend(json)
  },
  getRecentActivitySnapshot: async (): Promise<ExplorerRecentActivitySnapshot> => {
    const response = await fetch(`${getExplorerApiBase()}/api/v2/main-page/transactions`)
    if (!response.ok) {
      throw new Error(`HTTP ${response.status}`)
    }
    const json = (await response.json()) as Array<{
      status?: string | null
      transaction_types?: string[] | null
      gas_used?: number | string | null
      fee?: { value?: string | number | null } | string | null
    }>
    return summarizeRecentTransactions(json)
  },
}
