import {
  Box,
  Button,
  List,
  ListItem,
  ListSubheader,
  Typography,
  useTheme
} from '@mui/material'
import JSZip from 'jszip'
import { MuiFileInput } from 'mui-file-input'
import { Event, verifyEvent } from 'nostr-tools'
import { useEffect, useState } from 'react'
import { toast } from 'react-toastify'
import { LoadingSpinner } from '../../components/LoadingSpinner'
import { UserComponent } from '../../components/username'
import { MetadataController } from '../../controllers'
import { Meta, ProfileMetadata } from '../../types'
import {
  hexToNpub,
  parseJson,
  readContentOfZipEntry,
  shorten
} from '../../utils'
import styles from './style.module.scss'

export const VerifyPage = () => {
  const theme = useTheme()

  const textColor = theme.palette.getContrastText(
    theme.palette.background.paper
  )

  const [isLoading, setIsLoading] = useState(false)
  const [loadingSpinnerDesc, setLoadingSpinnerDesc] = useState('')

  const [selectedFile, setSelectedFile] = useState<File | null>(null)
  const [meta, setMeta] = useState<Meta | null>(null)

  const [metadata, setMetadata] = useState<{ [key: string]: ProfileMetadata }>(
    {}
  )

  useEffect(() => {
    if (meta) {
      const metadataController = new MetadataController()

      const users = [meta.submittedBy, ...meta.signers, ...meta.viewers]

      users.forEach((user) => {
        if (!(user in metadata)) {
          metadataController
            .findMetadata(user)
            .then((metadataEvent) => {
              const metadataContent =
                metadataController.extractProfileMetadataContent(metadataEvent)
              if (metadataContent)
                setMetadata((prev) => ({
                  ...prev,
                  [user]: metadataContent
                }))
            })
            .catch((err) => {
              console.error(
                `error occurred in finding metadata for: ${user}`,
                err
              )
            })
        }
      })
    }
  }, [meta])

  const handleVerify = async () => {
    if (!selectedFile) return
    setIsLoading(true)

    const zip = await JSZip.loadAsync(selectedFile).catch((err) => {
      console.log('err in loading zip file :>> ', err)
      toast.error(err.message || 'An error occurred in loading zip file.')
      return null
    })

    if (!zip) return

    setLoadingSpinnerDesc('Parsing meta.json')

    const metaFileContent = await readContentOfZipEntry(
      zip,
      'meta.json',
      'string'
    )

    if (!metaFileContent) {
      setIsLoading(false)
      return
    }

    const parsedMetaJson = await parseJson<Meta>(metaFileContent).catch(
      (err) => {
        console.log('err in parsing the content of meta.json :>> ', err)
        toast.error(
          err.message || 'error occurred in parsing the content of meta.json'
        )
        setIsLoading(false)
        return null
      }
    )

    setMeta(parsedMetaJson)
    setIsLoading(false)
  }

  const displayUser = (pubkey: string, verifySignature = false) => {
    const profile = metadata[pubkey]

    let isValidSignature = false

    if (verifySignature) {
      const signedEventString = meta ? meta.signedEvents[pubkey] : null
      if (signedEventString) {
        try {
          const signedEvent = JSON.parse(signedEventString)
          isValidSignature = verifyEvent(signedEvent)
        } catch (error) {
          console.error(
            `An error occurred in parsing and verifying the signature event for ${pubkey}`,
            error
          )
        }
      }
    }

    return (
      <>
        <UserComponent
          pubkey={pubkey}
          name={
            profile?.display_name || profile?.name || shorten(hexToNpub(pubkey))
          }
          image={profile?.picture}
        />

        {verifySignature && (
          <Typography component="label">
            ({isValidSignature ? 'Valid' : 'Not Valid'} Signature)
          </Typography>
        )}
      </>
    )
  }

  const displayExportedBy = () => {
    if (!meta || !meta.exportSignature) return null

    const exportSignatureString = meta.exportSignature

    try {
      const exportSignatureEvent = JSON.parse(exportSignatureString) as Event

      if (verifyEvent(exportSignatureEvent)) {
        return displayUser(exportSignatureEvent.pubkey)
      } else {
        toast.error(`Invalid export signature!`)
        return (
          <Typography component="label" sx={{ color: 'red' }}>
            Invalid export signature
          </Typography>
        )
      }
    } catch (error) {
      console.error(`An error occurred wile parsing exportSignature`, error)
      return null
    }
  }

  return (
    <>
      {isLoading && <LoadingSpinner desc={loadingSpinnerDesc} />}
      <Box className={styles.container}>
        {!meta && (
          <>
            <Typography component="label" variant="h6">
              Select exported zip file
            </Typography>

            <MuiFileInput
              placeholder="Select file"
              value={selectedFile}
              onChange={(value) => setSelectedFile(value)}
              InputProps={{
                inputProps: {
                  accept: '.zip'
                }
              }}
            />

            {selectedFile && (
              <Box sx={{ mt: 2, display: 'flex', justifyContent: 'center' }}>
                <Button onClick={handleVerify} variant="contained">
                  Verify
                </Button>
              </Box>
            )}
          </>
        )}

        {meta && (
          <>
            <List
              sx={{
                bgcolor: 'background.paper',
                marginTop: 2
              }}
              subheader={
                <ListSubheader className={styles.subHeader}>
                  Meta Info
                </ListSubheader>
              }
            >
              <ListItem
                sx={{
                  marginTop: 1,
                  gap: '15px'
                }}
              >
                <Typography variant="h6" sx={{ color: textColor }}>
                  Submitted By
                </Typography>
                {displayUser(meta.submittedBy)}
              </ListItem>

              <ListItem
                sx={{
                  marginTop: 1,
                  gap: '15px'
                }}
              >
                <Typography variant="h6" sx={{ color: textColor }}>
                  Exported By
                </Typography>
                {displayExportedBy()}
              </ListItem>

              {meta.signers.length > 0 && (
                <ListItem
                  sx={{
                    marginTop: 1,
                    flexDirection: 'column',
                    alignItems: 'flex-start'
                  }}
                >
                  <Typography variant="h6" sx={{ color: textColor }}>
                    Signers
                  </Typography>
                  <ul className={styles.usersList}>
                    {meta.signers.map((signer) => (
                      <li
                        key={signer}
                        style={{
                          color: textColor,
                          display: 'flex',
                          alignItems: 'center',
                          gap: '15px'
                        }}
                      >
                        {displayUser(signer, true)}
                      </li>
                    ))}
                  </ul>
                </ListItem>
              )}

              {meta.viewers.length > 0 && (
                <ListItem
                  sx={{
                    marginTop: 1,
                    flexDirection: 'column',
                    alignItems: 'flex-start'
                  }}
                >
                  <Typography variant="h6" sx={{ color: textColor }}>
                    Viewers
                  </Typography>
                  <ul className={styles.usersList}>
                    {meta.viewers.map((viewer) => (
                      <li key={viewer} style={{ color: textColor }}>
                        {displayUser(viewer)}
                      </li>
                    ))}
                  </ul>
                </ListItem>
              )}

              <ListItem
                sx={{
                  marginTop: 1,
                  flexDirection: 'column',
                  alignItems: 'flex-start'
                }}
              >
                <Typography variant="h6" sx={{ color: textColor }}>
                  Files
                </Typography>
                <ul>
                  {Object.keys(meta.fileHashes).map((file, index) => (
                    <li key={index} style={{ color: textColor }}>
                      {file}
                    </li>
                  ))}
                </ul>
              </ListItem>
            </List>
          </>
        )}
      </Box>
    </>
  )
}
