import { useState, useMemo } from 'react'
import { useAccount, useChainId } from 'wagmi'
import { useReadContract, useWriteContract, useWaitForTransactionReceipt } from 'wagmi'
import { CONTRACT_ADDRESSES } from '../../config/contracts'
import { GENERIC_STATE_CHANNEL_MANAGER_ABI } from '../../abis/GenericStateChannelManager'
import toast from 'react-hot-toast'
import { chain138, chain2138Testnet } from '../../config/networks'

const CHANNEL_STATUS = ['None', 'Open', 'Dispute', 'Closed'] as const

function getManagerAddress(chainId: number): `0x${string}` | undefined {
  if (chainId === 1) return CONTRACT_ADDRESSES.mainnet.GENERIC_STATE_CHANNEL_MANAGER as `0x${string}` | undefined
  if (chainId === 138) return CONTRACT_ADDRESSES.chain138.GENERIC_STATE_CHANNEL_MANAGER as `0x${string}` | undefined
  if (chainId === 2138) return CONTRACT_ADDRESSES.chain2138.GENERIC_STATE_CHANNEL_MANAGER as `0x${string}` | undefined
  return undefined
}

export default function StateChannels() {
  const { address } = useAccount()
  const chainId = useChainId()
  const managerAddress = getManagerAddress(chainId)

  const [counterparty, setCounterparty] = useState('')
  const [openAmount, setOpenAmount] = useState('')
  const [fundChannelId, setFundChannelId] = useState('')
  const [fundAmount, setFundAmount] = useState('')
  const [finalizeChannelId, setFinalizeChannelId] = useState('')

  const { data: channelCount = 0n } = useReadContract({
    address: managerAddress,
    abi: GENERIC_STATE_CHANNEL_MANAGER_ABI,
    functionName: 'getChannelCount',
  })
  const { data: paused } = useReadContract({
    address: managerAddress,
    abi: GENERIC_STATE_CHANNEL_MANAGER_ABI,
    functionName: 'paused',
  })
  const { writeContract, data: hash, isPending } = useWriteContract()
  const { isLoading: isConfirming } = useWaitForTransactionReceipt({ hash })

  const channelIds = useMemo(() => Array.from({ length: Number(channelCount) }, (_, i) => i), [channelCount])

  const openChannel = () => {
    if (!managerAddress || !counterparty || !openAmount) {
      toast.error('Enter counterparty and amount')
      return
    }
    const wei = BigInt(openAmount) * 10n ** 18n
    if (wei <= 0n) {
      toast.error('Amount must be > 0')
      return
    }
    writeContract(
      {
        address: managerAddress,
        abi: GENERIC_STATE_CHANNEL_MANAGER_ABI,
        functionName: 'openChannel',
        args: [counterparty as `0x${string}`],
        value: wei,
      },
      {
        onSuccess: () => { toast.success('Open channel tx submitted'); setCounterparty(''); setOpenAmount('') },
        onError: (e: unknown) => toast.error((e as Error).message),
      }
    )
  }

  const fundChannel = () => {
    if (!managerAddress || fundChannelId === '' || !fundAmount) {
      toast.error('Enter channel ID and amount')
      return
    }
    const wei = BigInt(fundAmount) * 10n ** 18n
    if (wei <= 0n) { toast.error('Amount must be > 0'); return }
    writeContract(
      {
        address: managerAddress,
        abi: GENERIC_STATE_CHANNEL_MANAGER_ABI,
        functionName: 'fundChannel',
        args: [BigInt(fundChannelId)],
        value: wei,
      },
      {
        onSuccess: () => { toast.success('Fund channel tx submitted'); setFundChannelId(''); setFundAmount('') },
        onError: (e: unknown) => toast.error((e as Error).message),
      }
    )
  }

  const doFinalizeClose = () => {
    if (!managerAddress || finalizeChannelId === '') { toast.error('Enter channel ID'); return }
    writeContract(
      {
        address: managerAddress,
        abi: GENERIC_STATE_CHANNEL_MANAGER_ABI,
        functionName: 'finalizeClose',
        args: [BigInt(finalizeChannelId)],
      },
      {
        onSuccess: () => { toast.success('Finalize close tx submitted'); setFinalizeChannelId('') },
        onError: (e: unknown) => toast.error((e as Error).message),
      }
    )
  }

  if (managerAddress == null) {
    return (
      <div className="rounded-xl bg-white/5 p-6 text-white/80">
        <p>
          Generic state channel manager not deployed on this chain. Set `GENERIC_STATE_CHANNEL_MANAGER`
          in config for Ethereum Mainnet, {chain138.name}, or {chain2138Testnet.name}.
        </p>
      </div>
    )
  }

  return (
    <div className="space-y-8">
      <div className="rounded-xl bg-white/5 p-6">
        <h2 className="text-xl font-semibold text-white mb-4">State Channels (with stateHash)</h2>
        {paused && <div className="mb-4 p-3 rounded-lg bg-amber-500/20 text-amber-200 text-sm">Contract is paused. Only close/finalize allowed.</div>}
        <p className="text-white/70 text-sm mb-4">
          Same as payment channels but settlement commits to a <code className="text-white/90">stateHash</code> (e.g. hash of game result or attestation). Open, fund, then close with stateHash + balances.
        </p>
        <div className="grid gap-6 md:grid-cols-2">
          <div className="space-y-2">
            <label className="block text-sm text-white/80">Open channel</label>
            <input type="text" placeholder="Counterparty 0x..." value={counterparty} onChange={(e) => setCounterparty(e.target.value)} className="w-full rounded-lg bg-black/30 border border-white/20 px-4 py-2 text-white placeholder-white/40" />
            <input type="text" placeholder="Amount (ETH)" value={openAmount} onChange={(e) => setOpenAmount(e.target.value)} className="w-full rounded-lg bg-black/30 border border-white/20 px-4 py-2 text-white placeholder-white/40" />
            <button onClick={openChannel} disabled={!!(isPending || isConfirming || paused)} className="rounded-lg bg-blue-600 px-4 py-2 text-white hover:bg-blue-700 disabled:opacity-50">{isPending || isConfirming ? 'Confirming...' : 'Open channel'}</button>
          </div>
          <div className="space-y-2">
            <label className="block text-sm text-white/80">Fund channel (participant B)</label>
            <input type="text" placeholder="Channel ID" value={fundChannelId} onChange={(e) => setFundChannelId(e.target.value)} className="w-full rounded-lg bg-black/30 border border-white/20 px-4 py-2 text-white placeholder-white/40" />
            <input type="text" placeholder="Amount (ETH)" value={fundAmount} onChange={(e) => setFundAmount(e.target.value)} className="w-full rounded-lg bg-black/30 border border-white/20 px-4 py-2 text-white placeholder-white/40" />
            <button onClick={fundChannel} disabled={!!(isPending || isConfirming || paused)} className="rounded-lg bg-blue-600 px-4 py-2 text-white hover:bg-blue-700 disabled:opacity-50">{isPending || isConfirming ? 'Confirming...' : 'Fund channel'}</button>
          </div>
        </div>
        <div className="mt-6 space-y-2">
          <label className="block text-sm text-white/80">Finalize close (after challenge window)</label>
          <input type="text" placeholder="Channel ID" value={finalizeChannelId} onChange={(e) => setFinalizeChannelId(e.target.value)} className="w-full max-w-xs rounded-lg bg-black/30 border border-white/20 px-4 py-2 text-white placeholder-white/40" />
          <button onClick={doFinalizeClose} disabled={!!(isPending || isConfirming)} className="rounded-lg bg-emerald-600 px-4 py-2 text-white hover:bg-emerald-700 disabled:opacity-50">{isPending || isConfirming ? 'Confirming...' : 'Finalize close'}</button>
        </div>
      </div>
      <StateChannelList managerAddress={managerAddress} channelIds={channelIds} currentUser={address} />
    </div>
  )
}

function StateChannelList({ managerAddress, channelIds, currentUser }: { managerAddress: `0x${string}`; channelIds: number[]; currentUser: string | undefined }) {
  return (
    <div className="rounded-xl bg-white/5 p-6">
      <h3 className="text-lg font-semibold text-white mb-4">Channels ({channelIds.length})</h3>
      {channelIds.length === 0 && <p className="text-white/60 text-sm">No channels yet.</p>}
      {channelIds.map((idx) => (
        <StateChannelRow key={idx} managerAddress={managerAddress} index={idx} currentUser={currentUser} />
      ))}
    </div>
  )
}

function StateChannelRow({ managerAddress, index, currentUser }: { managerAddress: `0x${string}`; index: number; currentUser: string | undefined }) {
  const { data: channelId } = useReadContract({
    address: managerAddress,
    abi: GENERIC_STATE_CHANNEL_MANAGER_ABI,
    functionName: 'getChannelIdByIndex',
    args: [BigInt(index)],
  })
  const { data: ch } = useReadContract({
    address: managerAddress,
    abi: GENERIC_STATE_CHANNEL_MANAGER_ABI,
    functionName: 'getChannel',
    args: channelId !== undefined ? [channelId] : undefined,
  })
  if (ch == null || channelId == null) return null
  const status = CHANNEL_STATUS[Number(ch.status)] ?? 'Unknown'
  const isMine = currentUser && (ch.participantA.toLowerCase() === currentUser.toLowerCase() || ch.participantB.toLowerCase() === currentUser.toLowerCase())
  return (
    <div className="rounded-lg border border-white/20 p-4 bg-black/20 mb-2">
      <div className="flex flex-wrap items-center gap-2 text-sm">
        <span className="text-white/60">ID: {String(channelId)}</span>
        <span className="text-white/80">A: {ch.participantA.slice(0, 10)}...</span>
        <span className="text-white/80">B: {ch.participantB.slice(0, 10)}...</span>
        <span className="text-white/80">Deposits: {(Number(ch.depositA) / 1e18).toFixed(4)} / {(Number(ch.depositB) / 1e18).toFixed(4)} ETH</span>
        <span className="text-white/60">{status}</span>
        {isMine && <span className="text-blue-300">(yours)</span>}
      </div>
      {Number(ch.status) === 2 && ch.disputeDeadline > 0n && (
        <p className="text-amber-200 text-xs mt-1">Dispute deadline: {new Date(Number(ch.disputeDeadline) * 1000).toISOString()}</p>
      )}
    </div>
  )
}
