import type { GetServerSideProps } from 'next'
import { useEffect, useMemo, useState } from 'react'
import { useRouter } from 'next/router'
import { Card, Address } from '@/libs/frontend-ui-primitives'
import Link from 'next/link'
import { configApi, type TokenListToken } from '@/services/api/config'
import EntityBadge from '@/components/common/EntityBadge'
import {
  inferDirectSearchTarget,
  inferTokenSearchTarget,
  normalizeExplorerSearchResults,
  suggestCuratedTokens,
  type RawExplorerSearchItem,
} from '@/utils/search'
import PageIntro from '@/components/common/PageIntro'
import { fetchPublicJson } from '@/utils/publicExplorer'
import { useUiMode } from '@/components/common/UiModeContext'

type SearchFilterMode = 'all' | 'gru' | 'x402' | 'wrapped'

interface SearchPageProps {
  initialQuery: string
  initialRawResults: RawExplorerSearchItem[]
  initialCuratedTokens: TokenListToken[]
}

export default function SearchPage({
  initialQuery,
  initialRawResults,
  initialCuratedTokens,
}: SearchPageProps) {
  const { mode } = useUiMode()
  const router = useRouter()
  const routerQuery = typeof router.query.q === 'string' ? router.query.q : ''
  const [query, setQuery] = useState(initialQuery)
  const [rawResults, setRawResults] = useState<RawExplorerSearchItem[]>(initialRawResults)
  const [loading, setLoading] = useState(false)
  const [hasSearched, setHasSearched] = useState(Boolean(initialQuery.trim()))
  const [error, setError] = useState<string | null>(null)
  const [curatedTokens, setCuratedTokens] = useState<TokenListToken[]>(initialCuratedTokens)
  const [savedQueries, setSavedQueries] = useState<string[]>([])
  const [filterMode, setFilterMode] = useState<SearchFilterMode>('all')

  const runSearch = async (rawQuery: string) => {
    const trimmedQuery = rawQuery.trim()
    if (!trimmedQuery) {
      setHasSearched(false)
      setRawResults([])
      setError(null)
      return
    }

    setHasSearched(true)
      setLoading(true)
      setError(null)
    try {
      const response = await fetch(
        `/api/v2/search?q=${encodeURIComponent(trimmedQuery)}`
      )
      const data = await response.json().catch(() => null)
      if (!response.ok) {
        setRawResults([])
        setError('Search is temporarily unavailable right now.')
        return
      }
      setRawResults(Array.isArray(data?.items) ? data.items : [])
    } catch (error) {
      console.error('Search failed:', error)
      setRawResults([])
      setError('Search is temporarily unavailable right now.')
    } finally {
      setLoading(false)
    }
  }

  useEffect(() => {
    if (initialCuratedTokens.length > 0) {
      setCuratedTokens(initialCuratedTokens)
      return
    }

    let active = true
    configApi.getTokenList().then((response) => {
      if (active) {
        setCuratedTokens((response.tokens || []).filter((token) => token.chainId === 138))
      }
    }).catch(() => {
      if (active) {
        setCuratedTokens([])
      }
    })
    return () => {
      active = false
    }
  }, [initialCuratedTokens])

  useEffect(() => {
    if (typeof window === 'undefined') return
    try {
      const stored = window.localStorage.getItem('explorer_saved_queries')
      const parsed = stored ? JSON.parse(stored) : []
      setSavedQueries(Array.isArray(parsed) ? parsed.filter((entry): entry is string => typeof entry === 'string') : [])
    } catch {
      setSavedQueries([])
    }
  }, [])

  useEffect(() => {
    if (!router.isReady) return
    if (!routerQuery.trim()) return
    if (routerQuery === initialQuery && initialRawResults.length > 0) {
      setQuery(routerQuery)
      setRawResults(initialRawResults)
      setHasSearched(true)
      return
    }
    setQuery(routerQuery)
    void runSearch(routerQuery)
  }, [initialQuery, initialRawResults, router.isReady, routerQuery])

  const handleSearch = async (e: React.FormEvent) => {
    e.preventDefault()
    const trimmedQuery = query.trim()
    if (!trimmedQuery) {
      return
    }

    setSavedQueries((current) => {
      const next = [trimmedQuery, ...current.filter((entry) => entry.toLowerCase() !== trimmedQuery.toLowerCase())].slice(0, 8)
      if (typeof window !== 'undefined') {
        try {
          window.localStorage.setItem('explorer_saved_queries', JSON.stringify(next))
        } catch {}
      }
      return next
    })

    const tokenTarget = inferTokenSearchTarget(trimmedQuery, curatedTokens)
    if (tokenTarget) {
      void router.push(tokenTarget.href)
      return
    }

    const directTarget = inferDirectSearchTarget(trimmedQuery)
    if (directTarget) {
      void router.push(directTarget.href)
      return
    }

    void router.replace(
      {
        pathname: router.pathname,
        query: { q: trimmedQuery },
      },
      undefined,
      { shallow: true },
    )
    await runSearch(trimmedQuery)
  }

  const trimmedQuery = query.trim()
  const tokenTarget = inferTokenSearchTarget(trimmedQuery, curatedTokens)
  const directTarget = inferDirectSearchTarget(trimmedQuery)
  const results = useMemo(
    () => normalizeExplorerSearchResults(trimmedQuery, rawResults, curatedTokens),
    [curatedTokens, rawResults, trimmedQuery],
  )
  const filteredResults = useMemo(() => {
    if (filterMode === 'gru') return results.filter((result) => result.is_gru_token)
    if (filterMode === 'x402') return results.filter((result) => result.is_x402_ready)
    if (filterMode === 'wrapped') return results.filter((result) => result.is_wrapped_transport)
    return results
  }, [filterMode, results])
  const curatedSuggestions = useMemo(
    () => suggestCuratedTokens(trimmedQuery, curatedTokens),
    [curatedTokens, trimmedQuery],
  )
  const groupedResults = useMemo(() => ({
    tokens: filteredResults.filter((result) => result.type === 'token'),
    addresses: filteredResults.filter((result) => result.type === 'address'),
    transactions: filteredResults.filter((result) => result.type === 'transaction'),
    blocks: filteredResults.filter((result) => result.type === 'block'),
    other: filteredResults.filter((result) => !['token', 'address', 'transaction', 'block'].includes(result.type)),
  }), [filteredResults])
  const resultSections = [
    { label: 'Tokens', items: groupedResults.tokens },
    { label: 'Addresses', items: groupedResults.addresses },
    { label: 'Transactions', items: groupedResults.transactions },
    { label: 'Blocks', items: groupedResults.blocks },
    { label: 'Other', items: groupedResults.other },
  ]

  return (
    <div className="container mx-auto px-4 py-6 sm:py-8">
      <PageIntro
        eyebrow="Explorer Lookup"
        title="Search"
        description={
          mode === 'guided'
            ? 'Search by address, transaction hash, block number, or token symbol. Direct identifiers can jump straight into detail pages, while broader terms fall back to indexed search.'
            : 'Search address, tx hash, block, or token symbol. Direct identifiers jump straight to detail pages.'
        }
        actions={[
          { href: '/tokens', label: 'Token shortcuts' },
          { href: '/addresses', label: 'Browse addresses' },
          { href: '/watchlist', label: 'Open watchlist' },
        ]}
      />

      <Card className="mb-6">
        <form onSubmit={handleSearch} className="flex flex-col gap-3 sm:flex-row sm:items-center">
          <input
            type="text"
            value={query}
            onChange={(e) => setQuery(e.target.value)}
            placeholder={mode === 'guided' ? 'Search by address, transaction hash, block number...' : 'Search tx / addr / block / token'}
            className="flex-1 px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500"
          />
          <button
            type="submit"
            disabled={loading || !trimmedQuery}
            className="w-full rounded-lg bg-primary-600 px-6 py-2 text-white hover:bg-primary-700 disabled:cursor-not-allowed disabled:opacity-50 sm:w-auto"
          >
            {loading ? 'Searching...' : 'Search'}
          </button>
        </form>
      </Card>

      {!loading && error && (
        <Card className="mb-6">
          <p className="text-sm text-gray-600 dark:text-gray-400">{error}</p>
          <div className="mt-4 flex flex-wrap gap-3 text-sm">
            <Link href="/tokens" className="text-primary-600 hover:underline">
              Try token shortcuts →
            </Link>
            <Link href="/addresses" className="text-primary-600 hover:underline">
              Browse addresses →
            </Link>
          </div>
        </Card>
      )}

      {!loading && tokenTarget && (
        <Card className="mb-6" title="Direct Token Match">
          <p className="text-sm text-gray-600 dark:text-gray-400">
            {mode === 'guided'
              ? 'This matches a curated Chain 138 token, so you can go straight to the token detail page instead of sifting through generic search results.'
              : 'Curated Chain 138 token match.'}
          </p>
          <div className="mt-4">
            <Link href={tokenTarget.href} className="text-primary-600 hover:underline">
              {tokenTarget.label} →
            </Link>
          </div>
        </Card>
      )}

      {!loading && !tokenTarget && directTarget && (
        <Card className="mb-6" title="Direct Match">
          <p className="text-sm text-gray-600 dark:text-gray-400">
            {mode === 'guided'
              ? 'This looks like a direct explorer identifier. You can open it without waiting for indexed search results.'
              : 'Direct explorer identifier detected.'}
          </p>
          <div className="mt-4">
            <Link href={directTarget.href} className="text-primary-600 hover:underline">
              {directTarget.label} →
            </Link>
          </div>
        </Card>
      )}

      {!loading && !tokenTarget && !directTarget && curatedSuggestions.length > 0 && (
        <Card className="mb-6" title="Curated Suggestions">
          <div className="space-y-3">
            <p className="text-sm text-gray-600 dark:text-gray-400">
              These listed Chain 138 assets are close to your query, which is often more useful than relying on a generic explorer result set alone.
            </p>
            <div className="flex flex-wrap gap-3">
              {curatedSuggestions.map((token) => (
                <Link key={token.address} href={`/tokens/${token.address}`} className="inline-flex items-center gap-2 rounded-full border border-gray-200 px-3 py-2 text-sm text-primary-600 hover:border-primary-300 hover:underline dark:border-gray-700">
                  <EntityBadge label="listed" tone="success" />
                  <span>{token.symbol || token.name || token.address}</span>
                </Link>
              ))}
            </div>
          </div>
        </Card>
      )}

      {results.length > 0 && (
        <Card title="Search Results">
          <div className="space-y-6">
            <div className="flex flex-wrap items-center gap-2">
              {([
                ['all', 'All results'],
                ['gru', 'GRU'],
                ['x402', 'x402 ready'],
                ['wrapped', 'Wrapped'],
              ] as const).map(([mode, label]) => (
                <button
                  key={mode}
                  type="button"
                  onClick={() => setFilterMode(mode)}
                  className={`rounded-full border px-3 py-1.5 text-sm transition ${
                    filterMode === mode
                      ? 'border-primary-500 bg-primary-50 text-primary-700 dark:border-primary-400 dark:bg-primary-950/40 dark:text-primary-200'
                      : 'border-gray-200 text-gray-600 hover:border-primary-300 hover:text-primary-600 dark:border-gray-700 dark:text-gray-300'
                  }`}
                >
                  {label}
                </button>
              ))}
              <Link href="/docs/gru" className="ml-auto text-sm text-primary-600 hover:underline">
                GRU guide →
              </Link>
            </div>
            {resultSections.map((section) =>
              section.items.length > 0 ? (
                <div key={section.label}>
                  <div className="mb-3 text-xs font-semibold uppercase tracking-[0.2em] text-gray-500 dark:text-gray-400">
                    {section.label}
                  </div>
                  <div className="space-y-4">
                    {section.items.map((result, index) => (
              <div key={result.data?.hash ?? result.data?.address ?? result.data?.number ?? index} className="border-b border-gray-200 pb-4 last:border-0 dark:border-gray-700">
                {result.type === 'block' && result.data.number && (
                  <Link href={result.href || `/blocks/${result.data.number}`} className="inline-flex flex-col gap-2 text-primary-600 hover:underline">
                    <div className="flex flex-wrap items-center gap-2">
                      <EntityBadge label="block" tone="neutral" />
                    </div>
                    <span className="font-medium text-gray-900 dark:text-white">Block #{result.data.number}</span>
                  </Link>
                )}
                {result.type === 'transaction' && result.data.hash && (
                  <Link href={result.href || `/transactions/${result.data.hash}`} className="inline-flex flex-col gap-2 text-primary-600 hover:underline">
                    <div className="flex flex-wrap items-center gap-2">
                      <EntityBadge label="transaction" tone="neutral" />
                    </div>
                    <Address address={result.data.hash} truncate showCopy={false} />
                  </Link>
                )}
                {(result.type === 'address' || result.type === 'token') && result.data.address && (
                  <Link
                    href={result.href || (result.type === 'token' ? `/tokens/${result.data.address}` : `/addresses/${result.data.address}`)}
                    className="inline-flex flex-col gap-2 text-primary-600 hover:underline"
                  >
                    <div className="flex flex-wrap items-center gap-2">
                      <EntityBadge
                        label={result.type === 'token' ? 'token' : 'address'}
                        tone={result.type === 'token' ? 'success' : 'neutral'}
                      />
                      {result.symbol && <EntityBadge label={result.symbol} tone="info" />}
                      {result.token_type && <EntityBadge label={result.token_type} tone="warning" />}
                      {result.is_curated_token && <EntityBadge label="listed" tone="success" />}
                      {result.is_gru_token && <EntityBadge label="GRU" tone="success" />}
                      {result.is_x402_ready && <EntityBadge label="x402 ready" tone="info" />}
                      {result.is_wrapped_transport && <EntityBadge label="wrapped" tone="warning" />}
                      {result.currency_code ? <EntityBadge label={result.currency_code} tone="neutral" /> : null}
                      {result.match_reason ? <EntityBadge label={result.match_reason} tone="info" className="normal-case tracking-normal" /> : null}
                      {result.matched_tags?.map((tag) => <EntityBadge key={tag} label={tag} />)}
                    </div>
                    <span className="font-medium text-gray-900 dark:text-white">
                      {result.name || result.symbol || result.label}
                    </span>
                    <Address address={result.data.address} truncate showCopy={false} />
                  </Link>
                )}
                <div className="mt-2 flex flex-wrap gap-x-3 gap-y-1 text-sm text-gray-500">
                  <span>Type: {result.type}</span>
                  <span>Chain: {result.chain_id ?? 138}</span>
                  <span>Priority: {(result.score ?? 0).toFixed(2)}</span>
                </div>
              </div>
                    ))}
                  </div>
                </div>
              ) : null,
            )}
          </div>
        </Card>
      )}

      {!loading && hasSearched && !error && filteredResults.length === 0 && (
        <Card title="No Results Found">
          <p className="text-sm text-gray-600 dark:text-gray-400">
            No explorer results matched <span className="font-medium text-gray-900 dark:text-white">{trimmedQuery}</span>
            {filterMode !== 'all' ? ` in the current ${filterMode} filter` : ''}.
            Try a full address, transaction hash, token symbol, or block number.
          </p>
          <div className="mt-4 flex flex-wrap gap-3 text-sm">
            <Link href="/tokens" className="text-primary-600 hover:underline">
              Token shortcuts →
            </Link>
            <Link href="/watchlist" className="text-primary-600 hover:underline">
              Watchlist →
            </Link>
            <Link href="/docs/gru" className="text-primary-600 hover:underline">
              GRU guide →
            </Link>
          </div>
        </Card>
      )}

      {!loading && !hasSearched && (
        <Card title="Popular Starting Points">
          <div className="space-y-4">
            <div className="flex flex-wrap gap-3 text-sm">
              <Link href="/search?q=cUSDT" className="text-primary-600 hover:underline">
                cUSDT →
              </Link>
              <Link href="/search?q=cUSDC" className="text-primary-600 hover:underline">
                cUSDC →
              </Link>
              <Link href="/search?q=cXAUC" className="text-primary-600 hover:underline">
                cXAUC →
              </Link>
              <Link href="/search?q=USDT" className="text-primary-600 hover:underline">
                USDT →
              </Link>
            </div>
            {savedQueries.length > 0 ? (
              <div>
                <div className="mb-2 text-xs font-semibold uppercase tracking-[0.2em] text-gray-500 dark:text-gray-400">
                  Recent Searches
                </div>
                <div className="flex flex-wrap gap-3 text-sm">
                  {savedQueries.map((savedQuery) => (
                    <Link key={savedQuery} href={`/search?q=${encodeURIComponent(savedQuery)}`} className="text-primary-600 hover:underline">
                      {savedQuery} →
                    </Link>
                  ))}
                </div>
              </div>
            ) : null}
          </div>
        </Card>
      )}
    </div>
  )
}

export const getServerSideProps: GetServerSideProps<SearchPageProps> = async (context) => {
  const initialQuery = typeof context.query.q === 'string' ? context.query.q.trim() : ''
  const tokenListResult = await fetchPublicJson<{ tokens?: TokenListToken[] }>('/api/config/token-list').catch(() => null)
  const initialCuratedTokens = Array.isArray(tokenListResult?.tokens)
    ? tokenListResult.tokens.filter((token) => token.chainId === 138)
    : []

  const shouldFetchSearch =
    Boolean(initialQuery) &&
    !inferTokenSearchTarget(initialQuery, initialCuratedTokens) &&
    !inferDirectSearchTarget(initialQuery)

  const searchResult = shouldFetchSearch
    ? await fetchPublicJson<{ items?: RawExplorerSearchItem[] }>(
        `/api/v2/search?q=${encodeURIComponent(initialQuery)}`,
      ).catch(() => null)
    : null

  return {
    props: {
      initialQuery,
      initialRawResults: Array.isArray(searchResult?.items) ? searchResult.items : [],
      initialCuratedTokens,
    },
  }
}
