import { useQuery } from '@based/react'
import { useMemo } from 'react'
import { SelectInput } from '../SelectInput/index.js'
import { TextInput } from '../TextInput/index.js'
import { Button } from '../Button/index.js'
import { IconButton } from '../IconButton/index.js'
import { Text } from '../Text/index.js'
import { Menu } from '../Menu/index.js'
import { Sheet } from '../Sheet/index.js'
import { Schema, SchemaTypeName } from '@based/schema'
import { Filter, FilterGroupItem } from '../../utils/common.js'

function countFilterItems(value: Filter): number {
  let count = value.items.length

  if (value.nested) {
    count += countFilterItems(value.nested.group)
  }

  return count
}

type FilterInputProps = {
  type: SchemaTypeName
  value?: Filter
  onChange: (value: Filter) => void
  schema?: Schema
}
function FilterInput({
  type,
  value = { operator: 'and', items: [] },
  onChange,
  schema,
}: FilterInputProps) {
  const typeFields = useMemo(() => {
    if (!schema) return

    return schema.types[type].props
  }, [schema, type])

  return (
    <Sheet>
      <Sheet.Trigger>
        {({ open }) => (
          <Button
            loading={!typeFields}
            forceHover={open}
            leadIcon="filter"
            variant="ghost"
            counter={
              countFilterItems(value) ? countFilterItems(value) : undefined
            }
          >
            Filter
          </Button>
        )}
      </Sheet.Trigger>
      <Sheet.Content>
        <div
          style={{
            width: 616,
          }}
        >
          <FilterGroupInput
            type={type}
            schema={schema}
            value={value}
            onChange={(_value) => {
              onChange(
                _value.items.length
                  ? _value
                  : _value.nested
                    ? _value?.nested.group
                    : _value,
              )
            }}
            onClearAll={() => {
              onChange(undefined)
            }}
          />
        </div>
      </Sheet.Content>
    </Sheet>
  )
}

type FilterGroupInputProps = {
  type: SchemaTypeName
  value: Filter
  onChange: (value: Filter) => void
  nested?: boolean
  onClearAll?: () => void
  schema?: Schema
}
function FilterGroupInput({
  type,
  value,
  onChange,
  nested,
  onClearAll,
  schema,
}: FilterGroupInputProps) {
  return (
    <div
      style={{
        display: 'flex',
        flexDirection: 'column',
        gap: 8,
      }}
    >
      {!nested && (
        <div
          style={{
            display: 'flex',
            alignItems: 'center',
            gap: 2,
            padding: '0 8px',
            height: 36,
          }}
        >
          <Text variant="subtext-medium" color="neutral60">
            Only show items where
          </Text>
          <Menu>
            <Menu.Trigger>
              {({ open }) => (
                <Button
                  variant="ghost"
                  size="small"
                  trailIcon="tiny-chevron-down"
                  forceHover={open}
                >
                  {value.operator === 'and' ? 'all' : 'any'}
                </Button>
              )}
            </Menu.Trigger>
            <Menu.Items>
              <Menu.ToggleItem
                value={value.operator === 'and'}
                onChange={() => {
                  onChange({
                    ...value,
                    operator: 'and',
                  })
                }}
              >
                all
              </Menu.ToggleItem>
              <Menu.ToggleItem
                value={value.operator === 'or'}
                onChange={() => {
                  onChange({
                    ...value,
                    operator: 'or',
                  })
                }}
              >
                any
              </Menu.ToggleItem>
            </Menu.Items>
          </Menu>
          <Text variant="subtext-medium" color="neutral60">
            below is true...
          </Text>
        </div>
      )}
      {value.items.map((item, index) => (
        <div
          key={index}
          style={{
            display: 'flex',
            gap: 8,
            paddingRight: 8,
            alignItems: 'center',
          }}
        >
          <FilterGroupItemInput
            schema={schema}
            type={type}
            value={item}
            onChange={(_value) => {
              onChange({
                ...value,
                items: value.items.map((e, i) => (i === index ? _value : e)),
              })
            }}
          />
          <IconButton
            icon="close"
            size="small"
            onClick={() => {
              onChange({
                ...value,
                items: value.items.filter((_, i) => i !== index),
              })
            }}
          />
        </div>
      ))}
      <div style={{ display: 'flex', gap: 8 }}>
        {!Boolean(value.items.length) && !nested ? (
          <Button
            variant="ghost"
            leadIcon="add"
            onClick={() => {
              onChange({
                ...value,
                items: [...value.items, { field: '', operator: '', value: '' }],
              })
            }}
          >
            Add filter
          </Button>
        ) : (
          <Menu>
            <Menu.Trigger>
              {({ open }) => (
                <Button variant="ghost" leadIcon="add" forceHover={open}>
                  Add
                </Button>
              )}
            </Menu.Trigger>
            <Menu.Items>
              <Menu.Item
                leadIcon="filter"
                onClick={() => {
                  onChange({
                    ...value,
                    items: [
                      ...value.items,
                      { field: '', operator: '', value: '' },
                    ],
                  })
                }}
              >
                Add filter
              </Menu.Item>
              {/* TODO correct icon */}
              <Menu.Item
                leadIcon="filter"
                onClick={() => {
                  onChange({
                    ...value,
                    nested: {
                      operator: 'and',
                      group: {
                        operator: 'and',
                        items: [{ field: '', operator: '', value: '' }],
                        nested: value.nested,
                      },
                    },
                  })
                }}
              >
                Add filter group
              </Menu.Item>
            </Menu.Items>
          </Menu>
        )}
        {((nested && !value.nested) ||
          (!nested && !value.nested && Boolean(value.items.length))) && (
          <Button leadIcon="close" onClick={onClearAll} variant="ghost">
            Clear all
          </Button>
        )}
      </div>
      {value.nested && (
        <>
          <div
            style={{
              display: 'flex',
              alignItems: 'center',
              gap: 2,
              height: 36,
              paddingLeft: 2,
            }}
          >
            <Menu>
              <Menu.Trigger>
                {({ open }) => (
                  <Button
                    variant="ghost"
                    size="small"
                    trailIcon="tiny-chevron-down"
                    forceHover={open}
                  >
                    {value.nested.operator}
                  </Button>
                )}
              </Menu.Trigger>
              <Menu.Items>
                <Menu.ToggleItem
                  value={value.nested.operator === 'and'}
                  onChange={() => {
                    onChange({
                      ...value,
                      nested: {
                        ...value.nested,
                        operator: 'and',
                      },
                    })
                  }}
                >
                  and
                </Menu.ToggleItem>
                <Menu.ToggleItem
                  value={value.nested.operator === 'or'}
                  onChange={() => {
                    onChange({
                      ...value,
                      nested: {
                        ...value.nested,
                        operator: 'or',
                      },
                    })
                  }}
                >
                  or
                </Menu.ToggleItem>
              </Menu.Items>
            </Menu>
            <Text variant="subtext-medium" color="neutral60">
              where
            </Text>
            <Menu>
              <Menu.Trigger>
                {({ open }) => (
                  <Button
                    variant="ghost"
                    size="small"
                    trailIcon="tiny-chevron-down"
                    forceHover={open}
                  >
                    {value.nested.group.operator === 'and' ? 'all' : 'any'}
                  </Button>
                )}
              </Menu.Trigger>
              <Menu.Items>
                <Menu.ToggleItem
                  value={value.nested.group.operator === 'and'}
                  onChange={() => {
                    onChange({
                      ...value,
                      nested: {
                        ...value.nested,
                        group: {
                          ...value.nested.group,
                          operator: 'and',
                        },
                      },
                    })
                  }}
                >
                  all
                </Menu.ToggleItem>
                <Menu.ToggleItem
                  value={value.nested.group.operator === 'or'}
                  onChange={() => {
                    onChange({
                      ...value,
                      nested: {
                        ...value.nested,
                        group: {
                          ...value.nested.group,
                          operator: 'or',
                        },
                      },
                    })
                  }}
                >
                  any
                </Menu.ToggleItem>
              </Menu.Items>
            </Menu>
            <Text variant="subtext-medium" color="neutral60">
              below is true...
            </Text>
          </div>
          <FilterGroupInput
            nested
            type={type}
            schema={schema}
            value={value.nested.group}
            onChange={(_value) => {
              onChange(
                _value.items.length
                  ? {
                      ...value,
                      nested: {
                        ...value.nested,
                        group: _value,
                      },
                    }
                  : {
                      ...value,
                      nested: _value.nested,
                    },
              )
            }}
            onClearAll={onClearAll}
          />
        </>
      )}
    </div>
  )
}

type FilterGroupItemInputProps = {
  type: SchemaTypeName
  value: FilterGroupItem
  onChange: (value: FilterGroupItem) => void
  schema?: Schema
}
function FilterGroupItemInput({
  type,
  value,
  onChange,
  schema,
}: FilterGroupItemInputProps) {
  const fieldOptions = useMemo(() => {
    if (!schema) return

    return Object.keys(schema.types[type].props).map((e) => ({
      value: e,
      label: e,
    }))
  }, [schema, type])
  const operatorOptions = useMemo(() => {
    return [
      { value: '=', label: 'is' },
      { value: '!=', label: 'is not' },
      { value: '>', label: '>' },
      { value: '<', label: '<' },
      { value: 'exists', label: 'exists' },
      { value: 'notExists', label: 'does not exist' },
    ]
  }, [])

  return (
    <div style={{ width: '100%', display: 'flex', gap: 8, paddingLeft: 8 }}>
      <SelectInput
        value={value.field}
        onChange={(field) => {
          onChange({ ...value, field: field as string })
        }}
        options={fieldOptions}
      />
      <SelectInput
        value={value.operator}
        onChange={(operator) => {
          onChange({ ...value, operator: operator as string })
        }}
        options={operatorOptions}
      />
      <TextInput
        value={value.value}
        onChange={(_value) => {
          onChange({ ...value, value: _value })
        }}
      />
    </div>
  )
}

export { FilterInput }
export type { FilterInputProps }
