import axios from 'axios'
import Button from 'components/Common/Button'
import Media from 'components/Common/Media'
import Modal from 'components/Common/Modal'
import { IconX } from 'components/Icons'
import getConfig from 'config/near'
import { useToast } from 'hooks/useToast'
import near from 'lib/near'
import useStore from 'lib/store'
import WalletHelper, { walletType } from 'lib/WalletHelper'
import { formatNearAmount } from 'near-api-js/lib/utils/format'
import { useRouter } from 'next/router'
import { useEffect, useState } from 'react'
import { sentryCaptureException } from 'lib/sentry'
import {
	FacebookIcon,
	FacebookShareButton,
	TelegramIcon,
	TelegramShareButton,
	TwitterIcon,
	TwitterShareButton,
} from 'react-share'
import { mutate } from 'swr'
import { decodeBase64, prettyBalance } from 'utils/common'
import retry from 'async-retry'

const SuccessTransactionModal = () => {
	const [showModal, setShowModal] = useState(false)
	const [token, setToken] = useState(null)
	const [txDetail, setTxDetail] = useState(null)
	const { currentUser, transactionRes, setTransactionRes } = useStore()
	const router = useRouter()
	const toast = useToast()

	useEffect(() => {
		const checkTxStatus = async () => {
			const txHash = router.query.transactionHashes.split(',')
			const txStatus = await near.getTransactionStatus({
				accountId: near.currentUser.accountId,
				txHash: txHash[txHash.length - 1],
			})
			if (window.sessionStorage.getItem('categoryToken')) {
				await submitCategoryCard(txStatus)
			}
			await processTransaction(txStatus)
		}

		if (currentUser && router.query.transactionHashes) {
			checkTxStatus()
		}
	}, [currentUser, router.query.transactionHashes])

	useEffect(() => {
		if (transactionRes) {
			const txLast = transactionRes[transactionRes.length - 1]
			if (txLast) {
				processTransaction(txLast)
			} else if (transactionRes.error) {
				processTransactionError(transactionRes.error.kind.ExecutionError)
			}
		}
	}, [transactionRes])

	const processTransactionError = (err) => {
		toast.show({
			text: <div className="font-semibold text-center text-sm">{err}</div>,
			type: 'error',
			duration: null,
		})
	}

	const processTransaction = async (txStatus) => {
		if (txStatus?.status?.SuccessValue !== undefined) {
			const { receipts_outcome } = txStatus
			const { actions, receiver_id } = txStatus.transaction

			for (const action of actions) {
				const { FunctionCall } = action
				const args = JSON.parse(decodeBase64(FunctionCall.args))

				if (FunctionCall.method_name === 'nft_buy') {
					const res = await axios.get(`${process.env.V2_API_URL}/token-series`, {
						params: {
							contract_id: receiver_id,
							token_series_id: args.token_series_id,
						},
					})
					setToken(res.data.data.results[0])
					setTxDetail({ ...FunctionCall, args })
					setShowModal(true)
				} else if (FunctionCall.method_name === 'buy') {
					const res = await axios.get(`${process.env.V2_API_URL}/token`, {
						params: {
							contract_id: args.nft_contract_id,
							token_id: args.token_id,
						},
					})
					setToken(res.data.data.results[0])
					setTxDetail({ ...FunctionCall, args })
					setShowModal(true)
				} else if (FunctionCall.method_name === 'add_offer') {
					const res = await axios.get(
						`${process.env.V2_API_URL}/${args.token_id ? 'token' : 'token-series'}`,
						{
							params: {
								contract_id: args.nft_contract_id,
								token_id: args.token_id,
								token_series_id: args.token_series_id,
							},
						}
					)
					setToken(res.data.data.results[0])
					setTxDetail({ ...FunctionCall, args })
					setShowModal(true)
				} else if (FunctionCall.method_name === 'add_bid') {
					const res = await axios.get(`${process.env.V2_API_URL}/token`, {
						params: {
							contract_id: args.nft_contract_id,
							token_id: args.token_id,
						},
					})
					setToken(res.data.data.results[0])
					setTxDetail({ ...FunctionCall, args })
					setShowModal(true)
				} else if (FunctionCall.method_name === 'cancel_bid') {
					const res = await axios.get(`${process.env.V2_API_URL}/token`, {
						params: {
							contract_id: args.nft_contract_id,
							token_id: args.token_id,
						},
					})
					setToken(res.data.data.results[0])
					setTxDetail({ ...FunctionCall, args })
					setShowModal(true)
				} else if (FunctionCall.method_name === 'accept_bid') {
					const res = await axios.get(`${process.env.V2_API_URL}/token`, {
						params: {
							contract_id: args.nft_contract_id,
							token_id: args.token_id,
						},
					})
					setToken(res.data.data.results[0])
					setTxDetail({ ...FunctionCall, args })
					setShowModal(true)
				} else if (FunctionCall.method_name === 'cancel_auction') {
					const res = await axios.get(`${process.env.V2_API_URL}/token`, {
						params: {
							contract_id: args.nft_contract_id,
							token_id: args.token_id,
						},
					})
					setToken(res.data.data.results[0])
					setTxDetail({ ...FunctionCall, args })
					setShowModal(true)
				} else if (FunctionCall.method_name === 'nft_set_series_price') {
					const res = await axios.get(`${process.env.V2_API_URL}/token-series`, {
						params: {
							contract_id: receiver_id,
							token_series_id: args.token_series_id,
						},
					})
					setToken(res.data.data.results[0])
					setTxDetail({ ...FunctionCall, args })
					setShowModal(true)
				} else if (FunctionCall.method_name === 'nft_approve') {
					const msgParse = JSON.parse(args?.msg)
					const res = await axios.get(`${process.env.V2_API_URL}/token`, {
						params: {
							contract_id:
								msgParse.market_type === 'accept_trade' ||
								msgParse.market_type === 'accept_trade_paras_series'
									? msgParse?.buyer_nft_contract_id
									: receiver_id,
							token_id:
								msgParse?.market_type === 'accept_trade' ||
								msgParse?.market_type === 'accept_trade_paras_series'
									? msgParse?.buyer_token_id
									: args.token_id,
						},
					})
					setToken(res.data.data.results[0])
					setTxDetail({ ...FunctionCall, args })
					setShowModal(true)
				} else if (FunctionCall.method_name === 'delete_market_data') {
					const res = await axios.get(`${process.env.V2_API_URL}/token`, {
						params: {
							contract_id: args.nft_contract_id,
							token_id: args.token_id,
						},
					})
					setToken(res.data.data.results[0])
					setTxDetail({ ...FunctionCall, args })
					setShowModal(true)
				} else if (FunctionCall.method_name === 'nft_create_series') {
					const logs = JSON.parse(receipts_outcome[0].outcome?.logs?.[0])
					const res = await axios.get(`${process.env.V2_API_URL}/token-series`, {
						params: {
							contract_id: receiver_id,
							token_series_id: logs.params.token_series_id,
						},
					})
					setToken(res.data.data.results[0])
					setTxDetail({ ...FunctionCall, args, logs })
					setShowModal(true)
				}
			}
		}
	}

	const onCloseModal = () => {
		const key = `${token.contract_id}::${token.token_series_id}${
			token.token_id ? `/${token.token_id}` : ''
		}`
		mutate(key)
		setShowModal(false)
		setToken(null)
		if (WalletHelper.activeWallet === walletType.sender) {
			setTransactionRes(null)
		} else {
			removeTxHash()
		}
	}

	const removeTxHash = () => {
		const query = router.query
		delete query.transactionHashes
		router.replace({ pathname: router.pathname, query }, undefined, { shallow: true })
	}

	const submitCategoryCard = async (res) => {
		const _categoryId = window.sessionStorage.getItem(`categoryToken`)
		const txLast = res
		const resFromTxLast = txLast.receipts_outcome[0].outcome.logs[0]
		const resOutcome = await JSON.parse(`${resFromTxLast}`)
		await retry(
			async () => {
				const res = await axios.post(
					`${process.env.V2_API_URL}/categories/tokens`,
					{
						account_id: currentUser,
						contract_id: txLast?.transaction?.receiver_id,
						token_series_id: resOutcome?.params?.token_series_id,
						category_id: _categoryId,
						storeToSheet: _categoryId === 'art-competition' ? `true` : `false`,
					},
					{
						headers: {
							authorization: await WalletHelper.authToken(),
						},
					}
				)
				if (res.status === 403 || res.status === 400) {
					sentryCaptureException(res.data?.message || `Token series still haven't exist`)
					return
				}
				window.sessionStorage.removeItem('categoryToken')
			},
			{
				retries: 20,
				factor: 2,
			}
		)
	}

	if (!showModal || !token) return null

	const tokenUrl = `${window.location.hostname}/token/${token.contract_id}::${
		token.token_series_id
	}${token.token_id ? `/${token.token_id}` : ''}`

	const explorerUrl = (txhash) =>
		getConfig(process.env.APP_ENV || 'development').explorerUrl + '/transactions/' + txhash

	const onClickSeeToken = () => {
		const url = `/token/${token.contract_id}::${token.token_series_id}${
			token.token_id ? `/${token.token_id}` : ''
		}${txDetail.method_name === 'add_offer' ? '?tab=offers' : ''}`
		router.push(url)
		onCloseModal()
	}

	const titleText = () => {
		if (txDetail.method_name === 'add_offer') {
			return 'Offer Success'
		} else if (txDetail.method_name === 'add_bid') {
			return 'Place Bid Success'
		} else if (txDetail.method_name === 'cancel_bid') {
			return 'Success Remove Bid'
		} else if (txDetail.method_name === 'accept_bid') {
			return 'Accept Bid Success'
		} else if (txDetail.method_name === 'nft_buy' || txDetail.method_name === 'buy') {
			return 'Purchase Success'
		} else if (txDetail.method_name === 'nft_set_series_price') {
			return 'Update Price Success'
		} else if (txDetail.method_name === 'nft_approve') {
			const msg = JSON.parse(txDetail.args.msg)
			if (msg.market_type === 'sale' && !msg.is_auction) {
				return 'Update Listing Success'
			} else if (msg.market_type === 'accept_offer') {
				return 'Accept Offer Success'
			} else if (msg.market_type === 'add_trade') {
				return 'Add Trade Success'
			} else if (msg.is_auction) {
				return 'Create Auction Success'
			} else if (
				msg.market_type === 'accept_trade' ||
				msg.market_type === 'accept_trade_paras_series'
			) {
				return 'Accept Trade Success'
			}
		} else if (txDetail.method_name === 'delete_market_data') {
			const args = txDetail.args
			if (args.is_auction) {
				return 'Remove Auction Success'
			}
			return 'Remove Listing Success'
		} else if (txDetail.method_name === 'nft_create_series') {
			return 'Create Card Success'
		} else {
			return 'Transaction Success'
		}
	}

	const descText = () => {
		if (txDetail.method_name === 'add_offer') {
			return (
				<>
					You successfully offer <b>{token.metadata.title}</b> for{' '}
					{formatNearAmount(txDetail.args.price)} Ⓝ
				</>
			)
		} else if (txDetail.method_name === 'add_bid') {
			return (
				<>
					You successfully bid of auction <b>{token.metadata.title}</b> for{' '}
					{prettyBalance(txDetail.args.amount, 24, 2)} Ⓝ
				</>
			)
		} else if (txDetail.method_name === 'cancel_bid') {
			return (
				<>
					You successfully remove bid auction <b>{token.metadata.title}</b> for{' '}
					{formatNearAmount(txDetail.args.amount)} Ⓝ
				</>
			)
		} else if (txDetail.method_name === 'accept_bid') {
			return (
				<>
					You successfully accept bid auction <b>{token.metadata.title}</b>
				</>
			)
		} else if (txDetail.method_name === 'cancel_auction') {
			return (
				<>
					You successfully remove auction <b>{token.metadata.title}</b>
				</>
			)
		} else if (txDetail.method_name === 'nft_buy' || txDetail.method_name === 'buy') {
			return (
				<>
					You successfully purchase <b>{token.metadata.title}</b>
				</>
			)
		} else if (txDetail.method_name === 'nft_set_series_price') {
			if (txDetail.args.price) {
				return (
					<>
						You successfully update <b>{token.metadata.title}</b> price to{' '}
						{formatNearAmount(txDetail.args.price)} Ⓝ
					</>
				)
			}
			return (
				<>
					You successfully remove the listing <b>{token.metadata.title}</b>
				</>
			)
		} else if (txDetail.method_name === 'nft_approve') {
			const msg = JSON.parse(txDetail.args.msg)
			if (msg.market_type === 'sale') {
				return (
					<>
						You successfully {msg.is_auction ? 'create auction' : 'update'}{' '}
						<b>{token.metadata.title}</b> with starting price {formatNearAmount(msg.price || 0)} Ⓝ
					</>
				)
			} else if (msg.market_type === 'accept_offer') {
				return (
					<>
						You successfully accept offer <b>{token.metadata.title}</b>
					</>
				)
			} else if (msg.market_type === 'add_trade') {
				return (
					<>
						You successfully trade your NFT <b>{token.metadata.title}</b>
					</>
				)
			} else if (
				msg.market_type === 'accept_trade' ||
				msg.market_type === 'accept_trade_paras_series'
			) {
				return (
					<>
						You successfully accept NFT <b>{token.metadata.title}</b>
					</>
				)
			}
		} else if (txDetail.method_name === 'delete_market_data') {
			return (
				<>
					You successfully remove the listing <b>{token.metadata.title}</b>
				</>
			)
		} else if (txDetail.method_name === 'nft_create_series') {
			return (
				<>
					You successfully create <b>{token.metadata.title}</b>
				</>
			)
		}
	}

	return (
		<Modal isShow={showModal} close={onCloseModal} className="p-8">
			<div className="max-w-sm w-full p-4 bg-gray-800 md:m-auto rounded-md relative">
				<div className="absolute right-0 top-0 pr-4 pt-4">
					<div className="cursor-pointer" onClick={onCloseModal}>
						<IconX />
					</div>
				</div>
				<div>
					<h1 className="text-2xl font-bold text-white tracking-tight">{titleText()}</h1>
					<p className="text-white mt-2">{descText()}</p>
					<div className="p-4">
						<div className="w-2/3 m-auto h-56">
							<Media
								className="rounded-lg overflow-hidden h-full w-full"
								url={token.metadata.media}
								videoControls={true}
								videoLoop={true}
								videoMuted={true}
								videoPadding={false}
							/>
						</div>
					</div>
					{router.query.transactionHashes && (
						<div className="p-3 bg-gray-700 rounded-md mt-2 mb-4">
							<p className="text-gray-300 text-sm">Transaction Hash</p>
							{router.query.transactionHashes.split(',').map((txhash) => (
								<a href={explorerUrl(txhash)} key={txhash} target="_blank" rel="noreferrer">
									<p className="text-white hover:underline cursor-pointer overflow-hidden text-ellipsis">
										{txhash}
									</p>
								</a>
							))}
						</div>
					)}
					<div className="flex justify-between px-1 mb-4">
						<p className="text-sm text-white">Share to:</p>
						<div className="flex gap-2">
							<FacebookShareButton url={tokenUrl} className="flex text-white">
								<FacebookIcon size={24} round />
							</FacebookShareButton>
							<TelegramShareButton url={tokenUrl} className="flex text-white">
								<TelegramIcon size={24} round />
							</TelegramShareButton>{' '}
							<TwitterShareButton
								title={`Checkout ${token.metadata.title} from collection ${token.metadata.collection} on @ParasHQ\n\n#paras #cryptoart #digitalart #tradingcards`}
								url={tokenUrl}
								className="flex text-white"
							>
								<TwitterIcon size={24} round />
							</TwitterShareButton>
						</div>
					</div>
					<Button size="md" isFullWidth onClick={onClickSeeToken}>
						See Token
					</Button>
				</div>
			</div>
		</Modal>
	)
}

export default SuccessTransactionModal