import { useEffect, useState } from 'react'
import { CreateSignatureEventContent, Meta } from '../types'
import { Mark } from '../types/mark'
import {
  parseCreateSignatureEvent,
  parseCreateSignatureEventContent,
  SigitMetaParseError,
  SigitStatus,
  SignStatus
} from '../utils'
import { toast } from 'react-toastify'
import { verifyEvent } from 'nostr-tools'
import { Event } from 'nostr-tools'

interface FlatMeta extends Meta, CreateSignatureEventContent, Partial<Event> {
  // Validated create signature event
  isValid: boolean

  // Calculated status fields
  signedStatus: SigitStatus
  signersStatus: {
    [signer: `npub1${string}`]: SignStatus
  }
}

/**
 * Custom use hook for parsing the Sigit Meta
 * @param meta Sigit Meta
 * @returns flattened Meta object with calculated signed status
 */
export const useSigitMeta = (meta: Meta): FlatMeta => {
  const [isValid, setIsValid] = useState(false)
  const [kind, setKind] = useState<number>()
  const [tags, setTags] = useState<string[][]>()
  const [created_at, setCreatedAt] = useState<number>()
  const [pubkey, setPubkey] = useState<string>() // submittedBy, pubkey from nostr event
  const [id, setId] = useState<string>()
  const [sig, setSig] = useState<string>()

  const [signers, setSigners] = useState<`npub1${string}`[]>([])
  const [viewers, setViewers] = useState<`npub1${string}`[]>([])
  const [fileHashes, setFileHashes] = useState<{
    [user: `npub1${string}`]: string
  }>({})
  const [markConfig, setMarkConfig] = useState<Mark[]>([])
  const [title, setTitle] = useState<string>('')
  const [zipUrl, setZipUrl] = useState<string>('')

  const [signedStatus, setSignedStatus] = useState<SigitStatus>(
    SigitStatus.Partial
  )
  const [signersStatus, setSignersStatus] = useState<{
    [signer: `npub1${string}`]: SignStatus
  }>({})

  useEffect(() => {
    if (!meta) return
    ;(async function () {
      try {
        const createSignatureEvent = await parseCreateSignatureEvent(
          meta.createSignature
        )

        const { kind, tags, created_at, pubkey, id, sig, content } =
          createSignatureEvent

        setIsValid(verifyEvent(createSignatureEvent))
        setKind(kind)
        setTags(tags)
        // created_at in nostr events are stored in seconds
        setCreatedAt(created_at * 1000)
        setPubkey(pubkey)
        setId(id)
        setSig(sig)

        const { title, signers, viewers, fileHashes, markConfig, zipUrl } =
          await parseCreateSignatureEventContent(content)

        setTitle(title)
        setSigners(signers)
        setViewers(viewers)
        setFileHashes(fileHashes)
        setMarkConfig(markConfig)
        setZipUrl(zipUrl)

        // Parse each signature event and set signer status
        for (const npub in meta.docSignatures) {
          try {
            const event = await parseCreateSignatureEvent(
              meta.docSignatures[npub as `npub1${string}`]
            )
            const isValidSignature = verifyEvent(event)
            setSignersStatus((prev) => {
              return {
                ...prev,
                [npub]: isValidSignature
                  ? SignStatus.Signed
                  : SignStatus.Invalid
              }
            })
          } catch (error) {
            setSignersStatus((prev) => {
              return {
                ...prev,
                [npub]: SignStatus.Invalid
              }
            })
          }
        }
        const signedBy = Object.keys(meta.docSignatures) as `npub1${string}`[]
        const isCompletelySigned = signers.every((signer) =>
          signedBy.includes(signer)
        )
        setSignedStatus(
          isCompletelySigned ? SigitStatus.Complete : SigitStatus.Partial
        )
      } catch (error) {
        if (error instanceof SigitMetaParseError) {
          toast.error(error.message)
        }
        console.error(error)
      }
    })()
  }, [meta])

  return {
    modifiedAt: meta.modifiedAt,
    createSignature: meta.createSignature,
    docSignatures: meta.docSignatures,
    keys: meta.keys,
    isValid,
    kind,
    tags,
    created_at,
    pubkey,
    id,
    sig,
    signers,
    viewers,
    fileHashes,
    markConfig,
    title,
    zipUrl,
    signedStatus,
    signersStatus
  }
}
