import { ApiResponse } from './client'
import {
  type BlockscoutTokenRef,
  fetchBlockscoutJson,
  normalizeAddressInfo,
  normalizeAddressTokenBalance,
  normalizeAddressTokenTransfer,
  normalizeTransactionSummary,
} from './blockscout'

export interface AddressInfo {
  address: string
  chain_id: number
  transaction_count: number
  token_count: number
  token_transfer_count?: number
  internal_transaction_count?: number
  logs_count?: number
  is_contract: boolean
  is_verified: boolean
  has_token_transfers: boolean
  has_tokens: boolean
  balance?: string
  creation_transaction_hash?: string
  label?: string
  tags: string[]
  token_contract?: {
    address: string
    symbol?: string
    name?: string
    decimals?: number
    type?: string
    total_supply?: string
    holders?: number
  }
}

export interface AddressTransactionsParams {
  chain_id: number
  from_address: string
  page?: number
  page_size?: number
}

export interface TransactionSummary {
  hash: string
  block_number: number
  from_address: string
  to_address?: string
  value: string
  status?: number
}

export interface AddressTokenBalance {
  token_address: string
  token_name?: string
  token_symbol?: string
  token_type?: string
  token_decimals: number
  value: string
  holder_count?: number
  total_supply?: string
}

export interface AddressTokenTransfer {
  transaction_hash: string
  block_number: number
  timestamp?: string
  from_address: string
  from_label?: string
  to_address: string
  to_label?: string
  token_address: string
  token_name?: string
  token_symbol?: string
  token_decimals: number
  value: string
  type?: string
}

export const addressesApi = {
  get: async (chainId: number, address: string): Promise<ApiResponse<AddressInfo>> => {
    const [raw, counters] = await Promise.all([
      fetchBlockscoutJson<{
        hash: string
        coin_balance?: string | null
        is_contract: boolean
        is_verified?: boolean
        has_token_transfers?: boolean
        has_tokens?: boolean
        creation_transaction_hash?: string | null
        name?: string | null
        token?: {
          address?: string | null
          symbol?: string | null
          name?: string | null
          decimals?: string | number | null
          type?: string | null
          total_supply?: string | null
          holders?: string | number | null
        } | null
        public_tags?: Array<{ label?: string; display_name?: string; name?: string } | string>
        private_tags?: Array<{ label?: string; display_name?: string; name?: string } | string>
        watchlist_names?: string[]
      }>(`/api/v2/addresses/${address}`),
      fetchBlockscoutJson<{
        transactions_count?: number
        token_balances_count?: number
        token_transfers_count?: number
        internal_transactions_count?: number
        logs_count?: number
      }>(`/api/v2/addresses/${address}/tabs-counters`),
    ])
    return { data: normalizeAddressInfo(raw, counters, chainId) }
  },
  /** Use when you need to check response.ok before setting state (avoids treating 4xx/5xx body as data). */
  getSafe: async (chainId: number, address: string): Promise<{ ok: boolean; data: AddressInfo | null }> => {
    try {
      const { data } = await addressesApi.get(chainId, address)
      return { ok: true, data }
    } catch {
      return { ok: false, data: null }
    }
  },
  getTransactionsSafe: async (
    chainId: number,
    address: string,
    page = 1,
    pageSize = 20
  ): Promise<{ ok: boolean; data: TransactionSummary[] }> => {
    try {
      const params = new URLSearchParams({
        page: page.toString(),
        page_size: pageSize.toString(),
      })
      const raw = await fetchBlockscoutJson<{ items?: unknown[] }>(`/api/v2/addresses/${address}/transactions?${params.toString()}`)
      const data = Array.isArray(raw?.items) ? raw.items.map((item) => normalizeTransactionSummary(item as never)) : []
      return { ok: true, data }
    } catch {
      return { ok: false, data: [] }
    }
  },

  getTransactions: async (
    chainId: number,
    address: string,
    page = 1,
    pageSize = 20
  ): Promise<ApiResponse<TransactionSummary[]>> => {
    const params = new URLSearchParams({
      page: page.toString(),
      page_size: pageSize.toString(),
    })
    const raw = await fetchBlockscoutJson<{ items?: unknown[] }>(`/api/v2/addresses/${address}/transactions?${params.toString()}`)
    const data = Array.isArray(raw?.items) ? raw.items.map((item) => normalizeTransactionSummary(item as never)) : []
    return { data }
  },
  getTokenBalancesSafe: async (address: string): Promise<{ ok: boolean; data: AddressTokenBalance[] }> => {
    try {
      const raw = await fetchBlockscoutJson<Array<{ token?: BlockscoutTokenRef | null; value?: string | null }>>(
        `/api/v2/addresses/${address}/token-balances`
      )
      return {
        ok: true,
        data: Array.isArray(raw) ? raw.map((item) => normalizeAddressTokenBalance(item)) : [],
      }
    } catch {
      return { ok: false, data: [] }
    }
  },
  getTokenTransfersSafe: async (
    address: string,
    page = 1,
    pageSize = 10
  ): Promise<{ ok: boolean; data: AddressTokenTransfer[] }> => {
    try {
      const params = new URLSearchParams({
        page: page.toString(),
        items_count: pageSize.toString(),
      })
      const raw = await fetchBlockscoutJson<{ items?: unknown[] }>(
        `/api/v2/addresses/${address}/token-transfers?${params.toString()}`
      )
      return {
        ok: true,
        data: Array.isArray(raw?.items) ? raw.items.map((item) => normalizeAddressTokenTransfer(item as never)) : [],
      }
    } catch {
      return { ok: false, data: [] }
    }
  },
}
