import { useEffect, useMemo, useState } from 'react'
import { Spinner } from 'src/admin/Spinner'
import { api } from 'src/api-helper'
import { encryptSymmetric, exportKeyToBase64URL, generateSymmetricKey } from 'src/crypto/symmetric-encrypt'

import { bigintToBase64URL } from '../vote/submitted/base64url'
import { State } from '../vote/vote-state'
import { MalwareCheckQRCode } from './MalwareCheckQRCode'

type CheckStatus = {
  confirmed: boolean | null
  created_at: null | string
  device_info: string
  match: boolean
  user_agent: string
}

type StatusResponse = {
  checks: CheckStatus[]
  verified_count: number
}

const LOCALHOST_IP = '192.168.4.124'

export const MalwareCheck = ({
  auth,
  election_id,
  state,
}: {
  auth: string
  election_id: string
  state: State & { submitted_at?: Date }
}) => {
  const [isOpen, setIsOpen] = useState(false)
  const [checkStatus] = useState<null | StatusResponse>(null)
  const [keyBase64URL, setKeyBase64URL] = useState<null | string>(null)
  const [otp, setOtp] = useState<null | string>(null)
  const [qrError, setQrError] = useState<null | string>(null)
  const [isLoading, setIsLoading] = useState(false)

  //   // Poll for malware check status
  //   useEffect(() => {
  //     if (!isOpen || !election_id || !auth) return

  //     const fetchStatus = async () => {
  //       try {
  //         const response = await fetch(`/api/election/${election_id}/malware-check-status?auth=${auth}`)
  //         if (response.ok) {
  //           const data: StatusResponse = await response.json()
  //           setCheckStatus(data)
  //         }
  //       } catch {
  //         // Silently fail
  //       }
  //     }

  //     fetchStatus()
  //     const interval = setInterval(fetchStatus, 5000) // Poll every 5 seconds

  //     return () => clearInterval(interval)
  //   }, [isOpen, election_id, auth])

  // Generate symmetric key, encrypt payload, and get OTP from server
  useEffect(() => {
    if (!isOpen) return

    if (!state.randomizer || otp || isLoading) return
    ;(async () => {
      setIsLoading(true)
      setQrError(null)

      try {
        // Generate symmetric key if not already generated
        const key = await generateSymmetricKey()
        // Export key to base64url for URL hash
        const exported = await exportKeyToBase64URL(key)
        setKeyBase64URL(exported)

        // Convert randomizers to base64url format
        const parts: string[] = []
        for (const questionId of Object.keys(state.randomizer)) {
          parts.push(questionId)
          parts.push(bigintToBase64URL(BigInt(state.randomizer[questionId])))
        }

        // Create compact payload: pipe-delimited format
        const payload = parts.join('|')

        // Encrypt payload using symmetric key
        const encrypted_randomizers = await encryptSymmetric(key, payload)

        // Send encrypted randomizers to server
        const response = await api('/malware-check/init', {
          auth_token: auth,
          election_id,
          encrypted_randomizers,
        })

        if (!response.ok) {
          const error = await response.json().catch(() => ({ error: 'Unknown error' }))
          throw new Error(error.error || 'Failed to initialize malware check')
        }

        const result = await response.json()
        if (result.otp) {
          setOtp(result.otp)
        } else {
          throw new Error('No OTP received from server')
        }
      } catch (error) {
        console.error('Failed to initialize malware check', error)
        setQrError(error instanceof Error ? error.message : 'Failed to initialize malware check')
      } finally {
        setIsLoading(false)
      }
    })()
  }, [state.randomizer, auth, election_id, otp, isLoading, isOpen])

  const qrUrl = useMemo(() => {
    if (!state.randomizer || !keyBase64URL || !otp) return ''

    // Build URL: /malware-check/:election_id/:auth_token/:otp#[symmetric_key]
    const protocol = typeof window !== 'undefined' && window.location.protocol === 'https:' ? 'https:' : 'http:'
    const host = typeof window !== 'undefined' ? window.location.host.replace('localhost', LOCALHOST_IP) : 'siv.org'
    return `${protocol}//${host}/malware-check/${election_id}/${auth}/${otp}#${keyBase64URL}`
  }, [auth, election_id, state.randomizer, keyBase64URL, otp])

  return (
    <div>
      <p className="py-6 mt-5 text-[12px]">
        <a className="cursor-pointer text-blue-500/90" onClick={() => setIsOpen(!isOpen)}>
          {isOpen ? '[-]' : '[+]'} Verify your vote {"wasn't"} changed by malware
        </a>
      </p>
      {isOpen &&
        (qrError ? (
          <p className="mb-2 text-xs text-red-600">⚠️ {qrError}</p>
        ) : (
          <div className="flex gap-4 items-center">
            {isLoading || !qrUrl ? (
              <div className="flex flex-col gap-4 items-center p-4 mb-2 text-xs rounded-md border border-solid text-black/50 border-black/15 h-[230px] w-[172px] justify-center">
                <Spinner /> Loading QR...
              </div>
            ) : (
              <MalwareCheckQRCode url={qrUrl} />
            )}

            <div className="max-w-sm">
              <p className="mb-3">
                As an additional layer of security, you can use multiple&nbsp;devices to verify your vote was submitted
                as intended.
              </p>

              <p className="text-[11px] text-black/60">
                <span className="font-medium text-black/70">How it works:</span> This rebuilds your encrypted vote
                submission, then lets you confirm the selections are as you intended.
              </p>

              <p className="mb-2 text-[11px] text-black/50">⚠️ This QR contains your private vote selections.</p>

              <a
                className="text-[11px] mt-7 block"
                href="https://docs.siv.org/verifiability/detecting-malware"
                rel="noopener noreferrer"
                target="_blank"
              >
                Learn more →
              </a>
              {checkStatus && checkStatus.verified_count > 0 && (
                <p className="mt-2 text-sm text-green-600">
                  Verified with {checkStatus.verified_count} separate device{checkStatus.verified_count > 1 ? 's' : ''}
                  {checkStatus.checks
                    .filter((c) => c.confirmed === true)
                    .slice(0, 1)
                    .map((c) => ` - ${c.device_info}`)
                    .join(', ')}
                </p>
              )}
            </div>
          </div>
        ))}
    </div>
  )
}
