import { useClient, useQuery } from '@based/react'
import { useRef, useState } from 'react'
import { Select } from '../../utils/common.js'
import { colors } from '../../utils/colors.js'
import { Modal } from '../Modal/index.js'
import { Button } from '../Button/index.js'
import { List } from '../List/index.js'
import { Icon } from '../Icon/index.js'
import { Text } from '../Text/index.js'
import { radius } from '../../utils/radius.js'
import { Menu } from '../Menu/index.js'
import { useMediaPreviews } from '../Media/index.js'
import { generateFinderProps } from '../../utils/heuristics.js'
import { Schema, SchemaTypeName } from '@based/schema'
import { Table } from '../Table/index.js'

// TODO single vs multiple version of this same component. do we handle that internally or create 2 seoarate components? separate ones work better for types.

type ReferencesInputProps = {
  type: SchemaTypeName
  value?: string[]
  onChange: (value: string[]) => void
  endpoints?: {
    schema?: string
  }
}

function ReferencesInput({
  type,
  value = [],
  onChange,
  endpoints,
}: ReferencesInputProps) {
  const client = useClient()
  const { data: schema } = useQuery(endpoints?.schema ?? 'db:schema') as {
    data?: Schema
  }
  const [select, setSelect] = useState<Select>([])
  const [open, setOpen] = useState(false)
  const fileInputRef = useRef<HTMLInputElement>()
  const [dragOver, setDragOver] = useState(false)
  const { addPreview } = useMediaPreviews()
  const { data: itemsData } = useQuery(value.length ? 'db' : undefined, {
    items: {
      $all: true,
      $list: {
        $find: {
          $traverse: value,
        },
      },
    },
  })

  async function uploadFiles(files: File[]) {
    const createdIds: string[] = []
    await Promise.allSettled(
      files.map(async (file) => {
        const { id } = await client.call('db:set', { type: 'file' })
        createdIds.push(id)

        if (file.type.includes('image')) {
          addPreview(id, URL.createObjectURL(file))
        }

        // not awaiting this promise so the outer allSettled can finish once we have all the IDs created and then we can update the UI in a single batch, otherwise if we'd call onChange in here the value of the selected variable would be stale
        client.stream('db:file-upload', {
          contents: file,
          fileName: file.name,
          mimeType: file.type,
          payload: { id },
        })
      }),
    )
    onChange([...value, ...createdIds])
    fileInputRef.current.value = ''
  }

  return (
    <>
      <div
        style={{
          width: '100%',
          display: 'flex',
          flexDirection: 'column',
          alignItems: 'start',
          gap: 8,
        }}
      >
        <div style={{ height: 128, width: '100%' }}>
          {Boolean(value.length) ? (
            <List
              data={itemsData?.items ?? []}
              fields={schema ? generateFinderProps(type, schema).fields : {}}
              itemActions={[
                {
                  label: 'Clear',
                  icon: 'close',
                  color: 'red',
                  onClick: (item) => {
                    onChange((value ?? []).filter((e) => e !== item.id))
                  },
                },
              ]}
            />
          ) : (
            <div
              style={{
                width: '100%',
                height: '100%',
                border: `1px solid ${colors.neutral20Adjusted}`,
                borderRadius: radius[12],
                padding: 8,
              }}
              onDrop={(e) => {
                e.preventDefault()
                setDragOver(false)

                const files = e.dataTransfer.files
                if (!files.length) return

                uploadFiles([...e.dataTransfer.files])
              }}
              onDragOver={(e) => {
                e.preventDefault()
                setDragOver(true)
              }}
              onDragLeave={() => {
                setDragOver(false)
              }}
            >
              <div
                style={{
                  display: 'flex',
                  justifyContent: 'center',
                  alignItems: 'center',
                  width: '100%',
                  height: '100%',
                  background: dragOver
                    ? colors.neutral10Adjusted
                    : 'transparent',
                  borderRadius: radius[4],
                }}
              >
                <div
                  style={{
                    display: 'flex',
                    justifyContent: 'center',
                    alignItems: 'center',
                    gap: 4,
                    flexDirection: 'column',
                    color: colors.neutral60,
                  }}
                >
                  {/* TODO correct icon */}
                  <Icon variant={type === 'file' ? 'page' : 'page'} />
                  <Text variant="subtext-medium" color="inherit">
                    {type === 'file'
                      ? 'Drag your file(s) here'
                      : 'Add reference(s) to other item(s)'}
                  </Text>
                </div>
              </div>
            </div>
          )}
        </div>
        <div style={{ display: 'flex', justifyContent: 'start', gap: 8 }}>
          {type === 'file' ? (
            <Menu>
              <Menu.Trigger>
                {({ open }) => (
                  <Button variant="border" leadIcon="add" forceHover={open}>
                    Add
                  </Button>
                )}
              </Menu.Trigger>
              <Menu.Items>
                <Menu.Item
                  leadIcon="arrow-up"
                  onClick={() => {
                    fileInputRef.current.click()
                  }}
                >
                  Upload new
                </Menu.Item>
                <Menu.Item
                  leadIcon="image"
                  onClick={() => {
                    setOpen(true)
                    setSelect(value)
                  }}
                >
                  Select from uploaded
                </Menu.Item>
              </Menu.Items>
            </Menu>
          ) : (
            <Button
              variant="border"
              leadIcon="add"
              onClick={() => {
                setOpen(true)
                setSelect(value)
              }}
            >
              Add
            </Button>
          )}

          {Boolean(value?.length) && (
            <Button
              variant="border"
              leadIcon="close"
              onClick={() => {
                onChange([])
              }}
            >
              Clear all
            </Button>
          )}
        </div>
      </div>
      {schema && (
        <Modal open={open} onOpenChange={setOpen} size="large">
          <Modal.Header
            title="Select reference"
            description="Pick one or more references below"
          />
          <Modal.Body>
            <div
              style={{
                display: 'flex',
                width: '100%',
                height: 'calc(100svh - 100px - 84px - 48px)',
                borderRadius: 12,
                overflow: 'hidden',
                border: `1px solid ${colors.neutral20Adjusted}`,
              }}
            >
              TODO add new based finder here
              {/* {type === 'file' ? (
                <BasedGrid
                  {...generateFinderProps(type, schema)}
                  select={select}
                  onSelectChange={setSelect}
                />
              ) : (
                <Table
                  {...generateFinderProps(type, schema)}
                  select={select}
                  onSelectChange={setSelect}
                />
              )} */}
            </div>
          </Modal.Body>
          <Modal.Actions>
            {({ close }) => (
              <>
                <Button
                  variant="border"
                  onClick={() => {
                    setSelect([])
                    close()
                  }}
                  keyHint="Esc"
                >
                  Cancel
                </Button>
                <Button
                  variant="fill"
                  keyHint="Enter"
                  onClick={() => {
                    onChange(select)
                    setSelect([])
                    close()
                  }}
                >
                  Save changes
                </Button>
              </>
            )}
          </Modal.Actions>
        </Modal>
      )}
      {type === 'file' && (
        <input
          style={{
            position: 'absolute',
            width: 1,
            height: 1,
            padding: 0,
            margin: -1,
            overflow: 'hidden',
            clip: 'rect(0, 0, 0, 0)',
            whiteSpace: 'nowrap',
            borderWidth: 0,
          }}
          ref={fileInputRef}
          type="file"
          multiple
          onChange={(e) => {
            const files = e.target.files
            if (!files.length) return

            uploadFiles([...e.target.files])
          }}
        />
      )}
    </>
  )
}

export { ReferencesInput }
export type { ReferencesInputProps }
