import React, { ChangeEvent, useRef, useState } from 'react'
import classNames from 'classnames'
import {
  AttachmentDisplayProps,
  AttachmentUploaderProps,
  ClearAttachmentButtonProps,
  UploadAttachmentButtonProps,
} from '../models'
import zocksStyle from './Attachment.module.scss'
import { getClassName, getMergedClassNames } from '../../common'

export const AttachmentUploader: React.FC<AttachmentUploaderProps> = ({
  uploadAttachment,
  attachmentRecipient,
  onAttachmentUploadStarted,
  onAttachmentUploadFinished,
  onAttachmentUploadFailed,
  components,
  styles,
}) => {
  const fileInputRef = useRef<HTMLInputElement>(null)
  const [isUploading, setUploading] = useState(false)
  const [hasError, setHasError] = useState(false)

  const buttonClickHandler = () => {
    fileInputRef.current?.click()
  }

  const uploadStarted = (file: File) => {
    setHasError(false)
    setUploading(true)
    onAttachmentUploadStarted && onAttachmentUploadStarted(file)
  }

  const uploadFinished = (file: File, fileId?: string) => {
    if (fileId) {
      onAttachmentUploadFinished && onAttachmentUploadFinished(file, fileId)
    } else {
      uploadFailed(file, new Error('No file id returned.'))
    }
  }

  const uploadFailed = (file: File, error: Error) => {
    console.error(error)
    setHasError(true)
    onAttachmentUploadFailed && onAttachmentUploadFailed(file)
  }

  const fileUploadHandler = async (e: ChangeEvent<HTMLInputElement>) => {
    const {
      target: { files },
    } = e
    if (files?.length) {
      const file = files[0]
      try {
        uploadStarted(file)
        const fileId = await uploadAttachment(file, attachmentRecipient)
        uploadFinished(file, fileId)
      } catch (error: any) {
        uploadFailed(file, error)
      } finally {
        setUploading(false)
      }
      e.target.value = ''
    }
  }

  const UploadAttachmentButtonElement = components?.UploadAttachment ?? UploadAttachmentButton
  const mergedStyles = getMergedClassNames(zocksStyle, styles)

  return (
    <div className={getClassName('attachment-uploader__container', mergedStyles)}>
      <UploadAttachmentButtonElement
        onClick={buttonClickHandler}
        disabled={isUploading}
        hasError={hasError}
        styles={styles}
      />
      <input
        ref={fileInputRef}
        className={getClassName('attachment-uploader__file-input', mergedStyles)}
        type='file'
        onChange={fileUploadHandler}
        disabled={isUploading}
        aria-hidden={true}
        data-testid='hidden-file-input'
      />
    </div>
  )
}

const UploadAttachmentButton: React.FC<UploadAttachmentButtonProps> = ({ onClick, disabled, hasError, styles }) => {
  const mergedStyles = getMergedClassNames(zocksStyle, styles)

  return (
    <button
      id='zocks__attachment-uploader__open-button'
      className={classNames(getClassName('attachment-uploader__open-button', mergedStyles), {
        [getClassName('attachment-uploader__open-button--error', mergedStyles)]: hasError,
      })}
      aria-label='Upload a file'
      onClick={onClick}
      disabled={disabled}
    >
      <label htmlFor='zocks__attachment-uploader__open-button'>📎</label>
    </button>
  )
}
export const AttachmentDisplay: React.FC<AttachmentDisplayProps> = ({
  attachment,
  onClearAttachment,
  hasAttachmentError,
  components,
  styles,
}) => {
  const mergedStyles = getMergedClassNames(zocksStyle, styles)

  if (hasAttachmentError) {
    return (
      <div className={getClassName('attachment-display__error', mergedStyles)}>
        {'Error while uploading attachment.'}
      </div>
    )
  }

  const ClearAttachmentButtonElement = components?.ClearAttachmentButton ?? ClearAttachmentButton

  if (attachment) {
    return (
      <div className={getClassName('attachment-display__container', mergedStyles)}>
        <span className={getClassName('attachment-display__name', mergedStyles)} title={attachment.fileName}>
          {attachment.fileName}
        </span>
        {onClearAttachment && <ClearAttachmentButtonElement onClick={onClearAttachment} styles={styles} />}
      </div>
    )
  }

  return null
}

const ClearAttachmentButton: React.FC<ClearAttachmentButtonProps> = ({ onClick, styles }) => {
  const mergedStyles = getMergedClassNames(zocksStyle, styles)

  return (
    <button
      id='zocks__attachment-display__remove-button'
      className={getClassName('attachment-display__remove-button', mergedStyles)}
      onClick={onClick}
      aria-label='Remove attachment'
    >
      <label htmlFor='zocks__attachment-display__remove-button'>❌</label>
    </button>
  )
}
