import type { GetServerSideProps } from 'next'
import { useCallback, useEffect, useMemo, useState } from 'react'
import { blocksApi, Block } from '@/services/api/blocks'
import { Card, Table, Address } from '@/libs/frontend-ui-primitives'
import Link from 'next/link'
import PageIntro from '@/components/common/PageIntro'
import ExplorerFreshnessDisclosure from '@/components/common/ExplorerFreshnessDisclosure'
import { formatTimestamp } from '@/utils/format'
import { fetchPublicJson } from '@/utils/publicExplorer'
import { normalizeBlock, normalizeTransaction } from '@/services/api/blockscout'
import type { Transaction } from '@/services/api/transactions'
import { transactionsApi } from '@/services/api/transactions'
import { summarizeChainActivity } from '@/utils/activityContext'
import PaginationControls from '@/components/common/PaginationControls'
import { useListPageQuery } from '@/utils/useListPageQuery'
import type { ExplorerStats } from '@/services/api/stats'
import type { MissionControlBridgeStatusResponse } from '@/services/api/missionControl'
import { resolveEffectiveFreshness, shouldExplainEmptyHeadBlocks } from '@/utils/explorerFreshness'
import { fetchExplorerTruthContext } from '@/utils/serverExplorerContext'

interface BlocksPageProps {
  initialBlocks: Block[]
  initialRecentTransactions: Transaction[]
  initialStats: ExplorerStats | null
  initialBridgeStatus: MissionControlBridgeStatusResponse | null
}

function serializeTransactions(transactions: Transaction[]): Transaction[] {
  return JSON.parse(
    JSON.stringify(
      transactions.map((transaction) => ({
        hash: transaction.hash,
        block_number: transaction.block_number,
        from_address: transaction.from_address,
        to_address: transaction.to_address ?? null,
        value: transaction.value,
        status: transaction.status ?? null,
        contract_address: transaction.contract_address ?? null,
        fee: transaction.fee ?? null,
        created_at: transaction.created_at,
      })),
    ),
  ) as Transaction[]
}

export default function BlocksPage({
  initialBlocks,
  initialRecentTransactions,
  initialStats,
  initialBridgeStatus,
}: BlocksPageProps) {
  const pageSize = 15
  const [blocks, setBlocks] = useState<Block[]>(initialBlocks)
  const [recentTransactions, setRecentTransactions] = useState<Transaction[]>(initialRecentTransactions)
  const [stats, setStats] = useState<ExplorerStats | null>(initialStats)
  const [bridgeStatus, setBridgeStatus] = useState<MissionControlBridgeStatusResponse | null>(initialBridgeStatus)
  const [loading, setLoading] = useState(initialBlocks.length === 0)
  const { page, setPage } = useListPageQuery()
  const chainId = parseInt(process.env.NEXT_PUBLIC_CHAIN_ID || '138')

  const loadBlocks = useCallback(async () => {
    setLoading(true)
    try {
      const response = await blocksApi.list({
        chain_id: chainId,
        page,
        page_size: pageSize,
        sort: 'number',
        order: 'desc',
      })
      setBlocks(response.data)
    } catch (error) {
      console.error('Failed to load blocks:', error)
      setBlocks([])
    } finally {
      setLoading(false)
    }
  }, [chainId, page, pageSize])

  useEffect(() => {
    if (page === 1 && initialBlocks.length > 0) {
      setBlocks(initialBlocks)
      setLoading(false)
      return
    }
    void loadBlocks()
  }, [initialBlocks, loadBlocks, page])

  useEffect(() => {
    if (initialRecentTransactions.length > 0) {
      setRecentTransactions(initialRecentTransactions)
      return
    }

    let active = true
    transactionsApi.listSafe(chainId, 1, 5)
      .then(({ ok, data }) => {
        if (active && ok && data.length > 0) {
          setRecentTransactions(data)
        }
      })
      .catch(() => {
        if (active) {
          setRecentTransactions([])
        }
      })

    return () => {
      active = false
    }
  }, [chainId, initialRecentTransactions])

  useEffect(() => {
    if (initialStats && initialBridgeStatus) {
      setStats(initialStats)
      setBridgeStatus(initialBridgeStatus)
      return
    }

    let active = true
    fetchExplorerTruthContext()
      .then((context) => {
        if (!active) return
        setStats((current) => current ?? context.initialStats)
        setBridgeStatus((current) => current ?? context.initialBridgeStatus)
      })
      .catch(() => undefined)

    return () => {
      active = false
    }
  }, [initialStats, initialBridgeStatus])

  const paginatedBlocks = useMemo(() => {
    const start = (page - 1) * pageSize
    return blocks.slice(start, start + pageSize)
  }, [blocks, page, pageSize])

  const showPagination = blocks.length > pageSize || page > 1
  const canGoNext = page * pageSize < blocks.length

  const activityContext = useMemo(
    () =>
      summarizeChainActivity({
        blocks,
        transactions: recentTransactions,
        latestBlockNumber: blocks[0]?.number ?? null,
        latestBlockTimestamp: blocks[0]?.timestamp ?? null,
        freshness: resolveEffectiveFreshness(stats, bridgeStatus),
        diagnostics: stats?.diagnostics ?? bridgeStatus?.data?.diagnostics ?? null,
      }),
    [blocks, bridgeStatus, stats, recentTransactions],
  )

  const columns = [
    {
      header: 'Block',
      accessor: (block: Block) => (
        <Link href={`/blocks/${block.number}`} className="font-medium text-primary-600 hover:underline">
          #{block.number}
        </Link>
      ),
    },
    {
      header: 'Age',
      accessor: (block: Block) => (
        <span className="text-sm text-gray-600 dark:text-gray-400">{formatTimestamp(block.timestamp)}</span>
      ),
    },
    {
      header: 'Miner',
      accessor: (block: Block) => (
        <Link href={`/addresses/${block.miner}`} className="text-primary-600 hover:underline">
          <Address address={block.miner} truncate showCopy={false} />
        </Link>
      ),
    },
    {
      header: 'Txs',
      accessor: (block: Block) => block.transaction_count,
    },
  ]

  return (
    <div className="container mx-auto px-4 py-4 sm:py-6">
      <PageIntro
        compact
        eyebrow="Chain Activity"
        title="Blocks"
        description="Recent Chain 138 blocks with miner links and transaction counts."
        actions={[
          { href: '/transactions', label: 'Transactions' },
          { href: '/search', label: 'Search' },
        ]}
      />

      <ExplorerFreshnessDisclosure
        context={activityContext}
        stats={stats}
        bridgeStatus={bridgeStatus}
        activityTitle="Block production"
        scopeLabel="Recent visible head blocks on this page."
      />

      {shouldExplainEmptyHeadBlocks(blocks, activityContext) ? (
        <p className="mb-4 rounded-lg border border-amber-200 bg-amber-50/70 px-3 py-2 text-sm text-amber-900 dark:border-amber-900/40 dark:bg-amber-950/20 dark:text-amber-100">
          Recent head blocks are empty; use the latest transaction block for visible activity.
        </p>
      ) : null}

      {loading ? (
        <Card>
          <p className="text-sm text-gray-600 dark:text-gray-400">Loading blocks...</p>
        </Card>
      ) : (
        <Table
          columns={columns}
          data={paginatedBlocks}
          emptyMessage="Recent blocks are unavailable right now."
          keyExtractor={(block) => String(block.number)}
        />
      )}

      {showPagination ? (
        <PaginationControls
          page={page}
          onPageChange={setPage}
          label="Blocks"
          ariaLabel="Blocks pagination"
          disabled={loading}
          hasNextPage={canGoNext}
          className="mt-6"
        />
      ) : null}
    </div>
  )
}

export const getServerSideProps: GetServerSideProps<BlocksPageProps> = async () => {
  const chainId = Number(process.env.NEXT_PUBLIC_CHAIN_ID || '138')
  const blocksResult = await fetchPublicJson<{ items?: unknown[] }>('/api/v2/blocks?page=1&page_size=15').catch(() => null)

  return {
    props: {
      initialBlocks: Array.isArray(blocksResult?.items)
        ? blocksResult.items.map((item) => normalizeBlock(item as never, chainId))
        : [],
      initialRecentTransactions: [],
      initialStats: null,
      initialBridgeStatus: null,
    },
  }
}
