import { useEffect, useMemo, useRef, useState } from 'react'
import { createPortal } from 'react-dom'
import { KEY_PREFIX_UPLOAD, routeIntercept, stateRecover, setTitle, routeTo } from '../../functions/Route'
import { formatTagTextContent, formatTagUsage } from '../../functions/Format'
import type { BackendArt } from '../../functions/BackendTypes'
import { API_BASE, CDN_BASE, BackendFetch } from '../../functions/Backend'
import { wtEvent } from '../../functions/Watchtower'
import { toast } from '../../functions/Context'
import './styles/Animation.css'

import MediaCanvas from '../layout/MediaCanvas'
import ModalEmbed from '../layout/ModalEmbed'
import HeaderLoading from '../layout/HeaderLoading'
import HeaderMessage from '../layout/HeaderMessage'
import HeaderError from '../layout/HeaderError'
import InputButtonRow from '../inputs/ButtonRow'
import InputButton from '../inputs/Button'
import InputBack from '../inputs/Back'

interface PropsForViewAnimation {
    id: string
}

export default function ViewAnimation({ id }: PropsForViewAnimation) {
    wtEvent('view_animation', { id })
    const embedRef = useRef<HTMLDialogElement>(null)

    const [data, setData] = useState(stateRecover<BackendArt | undefined>())
    const [error, setError] = useState<string | undefined>()
    const [isDownloading, setDownloading] = useState(false)
    const [isFullscreen, setFullscreen] = useState(false)
    const [isLoading, setLoading] = useState(!data)

    const isOwner = useMemo(() => Object.keys(localStorage).find((k) => k === `${KEY_PREFIX_UPLOAD}${id}`), [])
    const titleTags = data?.tags.map((t) => formatTagTextContent(t.label)).join(', ') ?? ''
    const titlePrefix = data ? (data.sticker ? 'Sticker' : 'Animation') : 'Item'
    const titleMessage = `View: ${titlePrefix} <ID: ${id}>`

    useEffect(() => {
        const start = Date.now()
        return () => {
            wtEvent('view_animation_duration', {
                id,
                ms: Date.now() - start,
            })
        }
    }, [])

    useEffect(() => {
        if (data) return
        BackendFetch<BackendArt>(`/art/${id}`)
            .then((resp) => {
                if (!resp.success) {
                    setError(resp.error)
                    return
                }
                setData(resp.json)
            })
            .catch((err) => {
                setError('Network Error')
                console.error(err)
            })
            .finally(() => setLoading(false))
    }, [])

    function onFullscreenClose() {
        wtEvent('action_animation_fullscreen_close', { id })
        setFullscreen(false)
    }

    function onFullscreenOpen() {
        wtEvent('action_animation_fullscreen_open', { id })
        setFullscreen(true)
    }

    function onEmbedClose() {
        wtEvent('action_animation_embed_close', { id })
        embedRef.current?.close()
    }

    function onEmbedOpen() {
        embedRef.current?.showModal()
        wtEvent('action_animation_embed_open', { id })
    }

    function onShareOpen() {
        const mobile = /iPhone|iPad|iPod|Android/i.test(navigator.userAgent)
        const url = window.location.href
        if (mobile) {
            navigator.share({ url, title: `${data?.title} ${titlePrefix} - gifuu` })
        } else {
            navigator.clipboard.writeText(url)
            toast('action-share', 'Copied URL to Clipboard!')
        }
        wtEvent('action_animation_share_open', { id, mobile })
    }

    function onDownload() {
        setDownloading(true)

        function save(source: Blob, extension: string) {
            const blob = URL.createObjectURL(source)
            const a = document.createElement('a')
            a.href = blob
            a.download = `${data?.title} [gifuu-${data?.id}].${extension}`
            a.click()
            URL.revokeObjectURL(blob)
        }

        try {
            if (!data) throw 'Missing Data'

            // We can use the already decoded frame for stickers
            if (data.sticker) {
                const renderer = document.querySelector<HTMLCanvasElement>('canvas.render')
                if (!renderer) {
                    throw 'Failed to find renderer'
                }
                renderer.toBlob(
                    (blob) => {
                        if (!blob) {
                            throw 'Failed to retrieve frame'
                        }
                        save(blob!, 'png')
                    },
                    'image/png',
                    0.9,
                )
            } else {
                // Download Standard Animation
                const url =
                    `${CDN_BASE}/${data.id}/standard.avif` +
                    `?utm_source=${window.location.hostname}&utm_medium=download&utm_term=${data.id}`

                fetch(url, { cache: 'force-cache' })
                    .then((resp) => resp.blob())
                    .then((resp) => save(resp, 'avif'))
            }

            wtEvent('action_animation_download', { id, sticker: data?.sticker })
        } catch (error) {
            toast('action-download', String(error))
            wtEvent('action_animation_download_failed', { id, reason: String(error) })
        } finally {
            setDownloading(false)
        }
    }

    function onDelete() {
        const accept = confirm('Delete this animation?')
        const upload_key = `${KEY_PREFIX_UPLOAD}${id}`
        const upload_token = localStorage.getItem(upload_key)

        wtEvent('action_animation_delete', { id, cancel: !accept })

        if (!upload_token) return
        if (!accept) return

        fetch(`${API_BASE}/art/${id}?token=${upload_token}`, { method: 'DELETE' })
            .then(async (res) => {
                if (!res.ok) {
                    alert(`Request Failed: ${await res.text()}`)
                    return
                }

                // Clear Local Data
                localStorage.removeItem(upload_key)
                routeTo('/personal')
            })
            .catch((error) => {
                wtEvent('action_animation_delete_failed', { id, reason: String(error) })
                console.error(error)
                alert('Network Error')
            })
    }

    if (isLoading) {
        return (
            <>
                <HeaderMessage label={titleMessage} />
                <HeaderLoading reason={undefined} />
            </>
        )
    }
    if (error || !data) {
        return (
            <>
                <HeaderMessage label={titleMessage} />
                <HeaderError reason={error!} />
            </>
        )
    }

    setTitle(`${titlePrefix}: ${data.title} (${titleTags})`)
    return (
        <>
            {createPortal(<ModalEmbed ref={embedRef} item={data} onClose={onEmbedClose} />, document.body)}
            {isFullscreen &&
                createPortal(
                    <div className="view-lightbox animation-fall-in" onClick={onFullscreenClose}>
                        <MediaCanvas id={data.id} background={true} />
                    </div>,
                    document.body,
                )}

            <HeaderMessage label={titleMessage} />
            <InputBack />

            <div className="view-animation">
                <div className="preview" onClick={onFullscreenOpen}>
                    <MediaCanvas id={id} background={false} />
                </div>

                <div className="metadata">
                    <p className="header">{data.title}</p>
                    <p className="subheader">
                        {data.width} &times; {data.height} &bull; {new Date(data.created).toLocaleString()} &bull;{' '}
                        {data.rating < 0.8 ? 'Public' : 'Unlisted'} ({(data.rating * 100) | 0}%)
                    </p>
                </div>

                <div className="tags">
                    {data.tags.map((t) => (
                        <>
                            <a
                                key={t.id}
                                className="item"
                                href={`/search?tag=${t.id}`}
                                onClick={(e) => routeIntercept(e, undefined, data)}>
                                {formatTagTextContent(t.label)}
                                <span className="usage">&bull; {formatTagUsage(t.usage)}</span>
                            </a>
                        </>
                    ))}
                </div>

                <InputButtonRow split={true}>
                    <InputButton
                        id="action-share"
                        label="Share"
                        onClick={onShareOpen}
                        disabled={false}
                        rainbow={false}
                        selected={false}
                    />
                    <InputButton
                        id="action-embed"
                        label="Embed"
                        onClick={onEmbedOpen}
                        disabled={false}
                        rainbow={false}
                        selected={false}
                    />
                    <InputButton
                        id="action-download"
                        label="Download"
                        onClick={onDownload}
                        disabled={isDownloading}
                        rainbow={isDownloading}
                        selected={false}
                    />
                    <InputButton
                        id="action-delete"
                        label="Delete"
                        onClick={onDelete}
                        disabled={!isOwner}
                        rainbow={false}
                        selected={false}
                    />
                </InputButtonRow>
            </div>
        </>
    )
}
