import * as React from 'react'

import {
	useState,
	useContext,
	useEffect,
} from '@wordpress/element'

import {
	__experimentalView as View,
	__experimentalVStack as VStack,
	__experimentalHStack as HStack,
	Modal,
	Button,
	Notice,
} from '@wordpress/components'

import {
	store as noticesStore,
} from '@wordpress/notices'

import {
	useDispatch,
} from '@wordpress/data'

import apiFetch from '@wordpress/api-fetch'

import {
	sha256,
} from 'js-sha256'

import {
	external as externalLinkIcon,
	cloudDownload,
	download,
	arrowLeft,
} from '@wordpress/icons'

import {
	ImportExportStringsContext,
} from '@ska/components'

import {
	debugLog,
} from '@ska/utils'

import {
	useImports,
} from './hooks'

import {
	EXPORTABLES,
} from './util'

type Demo = {
	title: string
	checksum: string
}

// @ts-expect-error
const demoData: {baseUrl: string, demos: Record<string, Demo>} = window?.ska_theme?.demos || {baseUrl: '', demos: {}}

const verifyChecksum = (slug: string, input: object, checksum: string) => {
	const data = JSON.stringify(input)
	const computedChecksum = sha256(data)
	const result = checksum === computedChecksum
	debugLog('Checksum', slug, result, {checksum, computedChecksum})
	return result
}

export interface DemoImportProps {
	baseUrl: string
	slug: string
	title: string
	checksum: string
	data: object
	onDone: () => void
	onCancel: () => void
}

const DemoImport: React.FC<DemoImportProps> = ({
	baseUrl,
	slug,
	title,
	checksum,
	data,
	onDone,
	onCancel,
}) => {

	const {
		importDemoLabel,
		summaryLabel,
	} = useContext(ImportExportStringsContext)

	const [imports, doImport] = useImports(data, {createEntities: true, demo: true})
	const [isImporting, setIsImporting] = useState(false)
	const [isDone, setIsDone] = useState(false)
	const [checksumValid, setChecksumValid] = useState(false)

	useEffect(() => {
		setChecksumValid(verifyChecksum(slug, data, checksum))
	}, [slug, data, checksum])

	const onImport = async () => {
		setIsImporting(true)
		await doImport()
		setIsImporting(false)
		setIsDone(true)
		onDone()
	}

	const IMPORTABLES = EXPORTABLES.filter(({value}) => value in imports)

	return (
		<VStack
			className='ska__import-export__demo-import'
			justify='start'
		>
			<h1>{title}</h1>
			{!checksumValid && (
				<Notice
					className='ska__import-export__demo-import__warning'
					isDismissible={false}
					status='warning'
					actions={[{
						label: 'Bypass checksum verification',
						className: 'is-destructive',
						variant: 'secondary',
						onClick: () => setChecksumValid(true),
					}]}
				>
					<div>
						<strong>{`Checksum verification failed`}</strong>
						<p>{`This probably means you're not using the latest version of the theme, but could also mean that the server that is serving demo content was compromised and is now providing malicious content — import at your own risk!`}</p>
					</div>
				</Notice>
			)}
			{isDone && (
				<div className='ska__import-export__demo-import__done'>
					<h2>{'Demo imported!'}</h2>
					<p>{'Close this modal and hit "Save".'}</p>
					<p>{'After saving all presets will be re-compiled automatically — hit "Save" again.'}</p>
				</div>
			)}
			{!isDone && (
				<div className='ska__import-export__demo-import__content'>
					<div className='ska__import-export__demo-import__content__image'>
						<img
							src={`${baseUrl}/get/${slug}.webp`}
							loading='lazy'
							alt={slug}
						/>
					</div>
					<div className='ska__import-export__demo-import__content__content'>
						<p><strong>{summaryLabel}</strong></p>
						<ul>
							{IMPORTABLES.map(({label, value}) => {
								const contents = imports[value]
								return contents.length > 0 ? (
									<li key={value}>
										{label} <code className='ska-code'>{contents.length}</code>
										<ul>
											{contents.map(({slug, label}) => {
												return (
													<li key={`${value}-${slug}`}>
														{label} <code className='ska-code'>{slug}</code>
													</li>
												)
											})}
										</ul>
									</li>
								) : null
							})}
						</ul>
					</div>
				</div>
			)}
			<HStack className='ska__import-export__demo-import__footer'>
				<Button
					variant='secondary'
					icon={arrowLeft}
					children={'Go back'}
					onClick={onCancel}
					disabled={isImporting || isDone}
				/>
				<Button
					className='ska__import-export__demo-import__footer__import-button'
					variant='primary'
					icon={download}
					children={importDemoLabel}
					aria-label={`${importDemoLabel}: ${title}`}
					onClick={onImport}
					disabled={!checksumValid || isDone}
					isBusy={isImporting}
				/>
			</HStack>
		</VStack>
	)
}

export interface DemoImportModalProps {
	onRequestClose: () => void
}

const DemoImportModal: React.FC<DemoImportModalProps> = ({
	onRequestClose,
}) => {

	const {
		importDemoLabel,
	} = useContext(ImportExportStringsContext)

	const {
		baseUrl,
		demos,
	} = demoData

	const {
		createErrorNotice,
	} = useDispatch(noticesStore)

	const [done, setDone] = useState(false)
	const [demo, setDemo] = useState<Omit<DemoImportProps, 'baseUrl' | 'onDone' | 'onCancel'> | false>(false)
	const [isLoading, setIsLoading] = useState<string | false>(false)

	const fetchDemo = async (slug: string) => {

		setIsLoading(slug)

		let result: object = {}
		await apiFetch({
				method: 'GET',
				url: `${baseUrl}/get/${slug}.json`,
				credentials: 'omit',
				headers: {
					Accept: 'application/json, */*;q=0.1',
				},
			}).then(response => {
				result = response as object
			}).catch(e => {
				createErrorNotice(`Failed downloading demo content: ${e.message}`, {type: 'snackbar'})
			}).finally(() => {
				setIsLoading(false)
			})

		return result
	}

	return (
		<Modal
			className='ska__import-export__import-demo-modal'
			title={importDemoLabel}
			size={done ? 'small' : 'fill'}
			onRequestClose={onRequestClose}
		>
			{demo !== false && (
				<DemoImport
					key={demo.slug}
					{...demo}
					baseUrl={baseUrl}
					onCancel={() => setDemo(false)}
					onDone={() => setDone(true)}
				/>
			)}
			{demo === false && (
				<View className='ska__import-export__demos'>
					{Object.entries(demos).map(([slug, demo]) => {

						const {
							title,
							checksum,
						} = demo as any as Demo

						const onImport = async () => {
							const fetchedDemo = await fetchDemo(slug)
							if('__file' in fetchedDemo && fetchedDemo.__file === 'ska-export') {
								setDemo({slug, title, checksum, data: fetchedDemo})
							}
						}

						return (
							<View key={slug} className='ska__import-export__demo'>
								<VStack spacing={0}>
									<h2>{title}</h2>
									<div className='ska__import-export__demo__image'>
										<img
											src={`${baseUrl}/get/${slug}.webp`}
											loading='lazy'
											alt={slug}
										/>
									</div>
									<HStack className='ska__import-export__demo__actions'>
										<Button
											variant='primary'
											icon={cloudDownload}
											children={importDemoLabel}
											aria-label={`${importDemoLabel}: ${title}`}
											onClick={onImport}
											isBusy={isLoading === slug}
											disabled={!!isLoading}
										/>
										<Button
											variant='link'
											icon={externalLinkIcon}
											iconPosition='right'
											children={'Live preview'}
											aria-label={`Live preview: ${title}`}
											href={`${baseUrl}/${slug}`}
											target='_blank'
											rel='noopener noreferrer'
										/>
									</HStack>
								</VStack>
							</View>
						)
					})}
				</View>
			)}
		</Modal>
	)
}

export default DemoImportModal
