import useSWRSubscription from "swr/subscription"
import { getDynamicBuilder, getLookupFn } from "@polkadot-api/metadata-builders"
import type { BlockInfo } from "@polkadot-api/observable-client"
import { distinct, filter, map, mergeMap } from "rxjs"

import { useUnstableProvider } from "./useUnstableProvider"
import { useMetadata } from "./useMetadata"

type Unlocking = {
    value: bigint
    era: number
}

export type AddressLedger = {
    stash: string
    total: bigint
    active: bigint
    unlocking: Unlocking[]
}

export const useLedger = ({ address }: { address: string | undefined }) => {
    const { chainHead$, chainId } = useUnstableProvider()
    const metadata = useMetadata()
    const { data: ledger } = useSWRSubscription(
        chainHead$ && address && chainId && metadata
            ? ["ledger", chainHead$, address, chainId, metadata]
            : null,
        ([_, chainHead$, address, chainId, metadata], { next }) => {
            const { finalized$, storage$ } = chainHead$
            const subscription = finalized$.pipe(
                filter(Boolean),
                mergeMap((blockInfo: BlockInfo) => {
                    const builder = getDynamicBuilder(getLookupFn(metadata))
                    const ledger = builder.buildStorage("Staking", "Ledger")
                    return storage$(blockInfo?.hash, "value", () =>
                        ledger?.keys.enc(address)
                    ).pipe(
                        filter(Boolean),
                        distinct(),
                        map((value: string) => ledger?.value.dec(value) as AddressLedger)
                    )
                }),
            )
            .subscribe({
                next(ledger: AddressLedger) {
                    next(null, ledger)
                },
                error: next,
            })
            return () => subscription.unsubscribe()
        }
    )
    return ledger
}
