import React, { useCallback, useState } from 'react'
import { View } from '../view'
import { Text } from '../text'
import { Button } from '../button'
import { UploadInput } from './Input.jsx'
import { LocalFilePreview } from './LocalFilePreview.jsx'
import { acceptsFile } from './acceptsFile.js'

function commitResourceValue(name, value, onChange) {
  onChange({
    target: {
      id: name,
      name,
      dataset: { ossyFileResourceReplace: 'true' },
      value: JSON.stringify(value),
    },
  })
}

function resourceIdFromValue(value) {
  if (value && typeof value === 'object' && !Array.isArray(value)) {
    return typeof value.resourceId === 'string' ? value.resourceId : null
  }
  return null
}

function resourceIdsFromValue(value) {
  if (!Array.isArray(value)) return []
  return value
    .map(item => (item && typeof item.resourceId === 'string' ? item.resourceId : null))
    .filter(Boolean)
}

/**
 * Default built-in file field: picker + local FileReader preview before a
 * `resourceId` is set. Production apps should register `@ossy/design-system/input/file` /
 * `@ossy/design-system/input/image` platform components for eager upload (see `@ossy/resources`).
 */
export function FileField({
  name,
  label,
  value,
  onChange,
  accept,
  min = 0,
  max = 1,
  disabled,
  required,
  style = {},
  ...rest
}) {
  const [localFile, setLocalFile] = useState(null)
  const [localFiles, setLocalFiles] = useState([])
  const [acceptError, setAcceptError] = useState(null)
  const multi = max > 1

  const onSinglePick = useCallback(
    e => {
      const file = e.target.files?.[0]
      e.target.value = ''
      if (!file) return
      if (!acceptsFile(file, accept)) {
        setAcceptError(file.name)
        return
      }
      setAcceptError(null)
      setLocalFile(file)
    },
    [accept],
  )

  const onMultiPick = useCallback(
    e => {
      const picked = Array.from(e.target.files || [])
      e.target.value = ''
      if (!picked.length) return
      const valid = picked.filter(f => acceptsFile(f, accept))
      if (valid.length !== picked.length) {
        setAcceptError('Some files were rejected by accept filter')
      } else {
        setAcceptError(null)
      }
      setLocalFiles(prev => {
        const next = [...prev, ...valid].slice(0, max)
        return next
      })
    },
    [accept, max],
  )

  const removeMultiLocal = useCallback(index => {
    setLocalFiles(prev => prev.filter((_, i) => i !== index))
  }, [])

  const removeMultiResource = useCallback(
    resourceId => {
      const ids = resourceIdsFromValue(value)
      commitResourceValue(
        name,
        ids.filter(id => id !== resourceId).map(id => ({ resourceId: id })),
        onChange,
      )
    },
    [name, onChange, value],
  )

  if (multi) {
    const refs = Array.isArray(value) ? value : []
    const canAdd = refs.length + localFiles.length < max

    return (
      <View gap="s" style={style} {...rest}>
        {refs.map(ref => (
          <View key={ref.resourceId} layout="row" gap="s" alignItems="center">
            <Text style={{ flex: 1, fontSize: 14 }}>{ref.resourceId}</Text>
            <Button
              type="button"
              variant="command-danger"
              prefix="close"
              size="s"
              disabled={disabled}
              onClick={() => removeMultiResource(ref.resourceId)}
              aria-label={`Remove ${label || name}`}
            />
          </View>
        ))}
        {localFiles.map((file, index) => (
          <View key={`${file.name}-${index}`} layout="row" gap="s" alignItems="center">
            <LocalFilePreview file={file} />
            <Text style={{ flex: 1, fontSize: 14 }}>{file.name}</Text>
            <Button
              type="button"
              variant="command-danger"
              prefix="close"
              size="s"
              disabled={disabled}
              onClick={() => removeMultiLocal(index)}
            />
          </View>
        ))}
        {canAdd && (
          <UploadInput
            id={name}
            name={name}
            accept={accept}
            disabled={disabled}
            required={required && refs.length === 0 && localFiles.length === 0}
            multiple
            onChange={onMultiPick}
          />
        )}
        {acceptError && (
          <Text style={{ fontSize: 12, color: 'var(--color-danger, crimson)' }}>{acceptError}</Text>
        )}
        <Text style={{ fontSize: 12, opacity: 0.65 }}>
          Stub field — register <code>@ossy/design-system/input/file</code> for upload.
        </Text>
      </View>
    )
  }

  const resourceId = resourceIdFromValue(value)

  return (
    <View gap="s" style={style} {...rest}>
      {(localFile || resourceId) && (
        <View layout="row" gap="s" alignItems="center">
          {localFile && <LocalFilePreview file={localFile} size="48px" />}
          {resourceId && !localFile && (
            <Text style={{ fontSize: 14 }}>{resourceId}</Text>
          )}
          {localFile && (
            <Text style={{ flex: 1, fontSize: 14 }}>{localFile.name}</Text>
          )}
        </View>
      )}
      <UploadInput
        id={name}
        name={name}
        accept={accept}
        disabled={disabled}
        required={required && !resourceId && !localFile}
        onChange={onSinglePick}
      />
      {acceptError && (
        <Text style={{ fontSize: 12, color: 'var(--color-danger, crimson)' }}>
          File not accepted: {acceptError}
        </Text>
      )}
      {!resourceId && (
        <Text style={{ fontSize: 12, opacity: 0.65 }}>
          Stub field — register <code>@ossy/design-system/input/file</code> for upload.
        </Text>
      )}
    </View>
  )
}
