import { useState } from 'react'
import { uploadNip95Media } from '@/lib/nip95'
import { Button } from './ui'
import { t } from '@/lib/i18n'
import Image from 'next/image'
import { UnlockAccountModal } from './UnlockAccountModal'

interface ImageUploadFieldProps {
  id: string
  label?: string | undefined
  value?: string | undefined
  onChange: (url: string) => void
  helpText?: string | undefined
}

function ImagePreview({ value }: { value: string }): React.ReactElement {
  return (
    <div className="relative w-32 h-32 rounded-lg overflow-hidden border border-neon-cyan/20">
      <Image
        src={value}
        alt={t('presentation.field.picture')}
        fill
        className="object-cover"
      />
    </div>
  )
}

function UploadButtonLabel({ uploading, value }: { uploading: boolean; value: string | undefined }): React.ReactElement {
  if (uploading) {
    return <span>{t('presentation.field.picture.uploading')}</span>
  }
  return <span>{value ? t('presentation.field.picture.change') : t('presentation.field.picture.upload')}</span>
}

function RemoveButton({ value, onChange }: { value: string | undefined; onChange: (url: string) => void }): React.ReactElement | null {
  if (!value) {
    return null
  }
  return (
    <Button
      type="button"
      variant="danger"
      size="small"
      onClick={() => onChange('')}
    >
      {t('presentation.field.picture.remove')}
    </Button>
  )
}

function ImageUploadControls({
  id,
  uploading,
  value,
  onChange,
  onFileSelect,
}: {
  id: string
  uploading: boolean
  value: string | undefined
  onChange: (url: string) => void
  onFileSelect: (e: React.ChangeEvent<HTMLInputElement>) => Promise<void>
}): React.ReactElement {
  return (
    <div className="flex items-center gap-2">
      <label htmlFor={id} className="cursor-pointer">
        <span className="inline-flex items-center justify-center px-4 py-2 text-sm font-medium rounded-lg transition-all border bg-neon-cyan/20 hover:bg-neon-cyan/30 text-neon-cyan border-neon-cyan/50 hover:shadow-glow-cyan">
          <UploadButtonLabel uploading={uploading} value={value} />
        </span>
      </label>
      <input
        id={id}
        type="file"
        accept="image/png,image/jpeg,image/jpg,image/webp"
        className="hidden"
        onChange={(e) => {
          void onFileSelect(e)
        }}
        disabled={uploading}
      />
      <RemoveButton value={value} onChange={onChange} />
    </div>
  )
}

async function processFileUpload(file: File, onChange: (url: string) => void, setError: (error: string | null) => void): Promise<void> {
  const media = await uploadNip95Media(file)
  if (media.type === 'image') {
    onChange(media.url)
  } else {
    setError(t('presentation.field.picture.error.imagesOnly'))
  }
}

type ImageUploadState = {
  uploading: boolean
  error: string | null
  handleFileSelect: (e: React.ChangeEvent<HTMLInputElement>) => Promise<void>
  showUnlockModal: boolean
  setShowUnlockModal: (show: boolean) => void
  handleUnlockSuccess: () => Promise<void>
}

function useImageUpload(onChange: (url: string) => void): ImageUploadState {
  const [uploading, setUploading] = useState(false)
  const [error, setError] = useState<string | null>(null)
  const [showUnlockModal, setShowUnlockModal] = useState(false)
  const [pendingFile, setPendingFile] = useState<File | null>(null)

  const handleFileSelect = createHandleFileSelect({
    onChange,
    setError,
    setUploading,
    setPendingFile,
    setShowUnlockModal,
  })

  const handleUnlockSuccess = createHandleUnlockSuccess({
    pendingFile,
    onChange,
    setError,
    setPendingFile,
    setShowUnlockModal,
    setUploading,
  })

  return { uploading, error, handleFileSelect, showUnlockModal, setShowUnlockModal, handleUnlockSuccess }
}

function createHandleFileSelect(params: {
  onChange: (url: string) => void
  setError: (error: string | null) => void
  setUploading: (uploading: boolean) => void
  setPendingFile: (file: File | null) => void
  setShowUnlockModal: (show: boolean) => void
}): (event: React.ChangeEvent<HTMLInputElement>) => Promise<void> {
  return async (event: React.ChangeEvent<HTMLInputElement>): Promise<void> => {
    const file = readFirstFile(event)
    if (!file) {
      return
    }

    params.setError(null)
    params.setUploading(true)

    try {
      await processFileUpload(file, params.onChange, params.setError)
    } catch (uploadError) {
      const uploadErr = normalizeError(uploadError)
      if (isUnlockRequiredError(uploadErr)) {
        params.setPendingFile(file)
        params.setShowUnlockModal(true)
        params.setError(null)
      } else {
        params.setError(uploadErr.message ?? t('presentation.field.picture.error.uploadFailed'))
      }
    } finally {
      params.setUploading(false)
    }
  }
}

function createHandleUnlockSuccess(params: {
  pendingFile: File | null
  onChange: (url: string) => void
  setError: (error: string | null) => void
  setPendingFile: (file: File | null) => void
  setShowUnlockModal: (show: boolean) => void
  setUploading: (uploading: boolean) => void
}): () => Promise<void> {
  return async (): Promise<void> => {
    await retryPendingUpload(params)
  }
}

function readFirstFile(event: React.ChangeEvent<HTMLInputElement>): File | null {
  return event.target.files?.[0] ?? null
}

function normalizeError(error: unknown): Error {
  return error instanceof Error ? error : new Error(String(error))
}

function isUnlockRequiredError(error: Error): boolean {
  if (error.message === 'UNLOCK_REQUIRED') {
    return true
  }
  if (typeof error === 'object' && error !== null && 'unlockRequired' in error) {
    return (error as { unlockRequired?: boolean }).unlockRequired === true
  }
  return false
}

async function retryPendingUpload(params: {
  pendingFile: File | null
  onChange: (url: string) => void
  setError: (error: string | null) => void
  setPendingFile: (file: File | null) => void
  setShowUnlockModal: (show: boolean) => void
  setUploading: (uploading: boolean) => void
}): Promise<void> {
  params.setShowUnlockModal(false)
  if (!params.pendingFile) {
    return
  }

  params.setUploading(true)
  params.setError(null)
  try {
    await processFileUpload(params.pendingFile, params.onChange, params.setError)
    params.setPendingFile(null)
  } catch (retryError) {
    params.setError(retryError instanceof Error ? retryError.message : t('presentation.field.picture.error.uploadFailed'))
  } finally {
    params.setUploading(false)
  }
}

export function ImageUploadField({ id, label, value, onChange, helpText }: ImageUploadFieldProps): React.ReactElement {
  const { uploading, error, handleFileSelect, showUnlockModal, setShowUnlockModal, handleUnlockSuccess } = useImageUpload(onChange)
  const displayLabel = label ?? t('presentation.field.picture')
  const displayHelpText = helpText ?? t('presentation.field.picture.help')

  return (
    <>
    <div className="space-y-2">
      <label htmlFor={id} className="block text-sm font-medium text-neon-cyan">
        {displayLabel}
      </label>
      {value && <ImagePreview value={value} />}
      <ImageUploadControls
        id={id}
        uploading={uploading}
        value={value}
        onChange={onChange}
        onFileSelect={handleFileSelect}
      />
      {error && <p className="text-sm text-red-400">{error}</p>}
      {displayHelpText && <p className="text-sm text-cyber-accent">{displayHelpText}</p>}
    </div>
      {showUnlockModal && (
        <UnlockAccountModal
          onSuccess={() => {
            void handleUnlockSuccess()
          }}
          onClose={() => {
            setShowUnlockModal(false)
          }}
        />
      )}
    </>
  )
}
