import React from 'react';
import { ChevronDown } from 'lucide-react';
import { YStack, XStack } from '@tamagui/stacks';
import { SizableText as Text } from '@tamagui/text';
import { Input, TextArea } from 'tamagui';
import { Select } from '@tamagui/select';
import { withAlpha } from './colors';
import { useAdminTheme } from '../theme';

type FieldProps = {
  label: React.ReactNode;
  hint?: string;
  error?: string | null;
  children: React.ReactNode;
};

export function MobileField({ label, hint, error, children }: FieldProps) {
  const { text, muted, danger } = useAdminTheme();

  return (
    <YStack space="$1.5">
      {typeof label === 'string' || typeof label === 'number' ? (
        <Text fontSize="$sm" fontWeight="800" color={text}>
          {label}
        </Text>
      ) : (
        label
      )}
      {children}
      {hint ? (
        <Text fontSize="$xs" color={muted}>
          {hint}
        </Text>
      ) : null}
      {error ? (
        <Text fontSize="$xs" color={danger}>
          {error}
        </Text>
      ) : null}
    </YStack>
  );
}

type ControlProps = {
  hasError?: boolean;
  compact?: boolean;
};

type MobileSelectProps = React.ComponentPropsWithoutRef<'select'> & ControlProps & {
  placeholder?: string;
  containerStyle?: React.CSSProperties;
};

export const MobileColorInput = React.forwardRef<
  HTMLInputElement,
  React.ComponentPropsWithoutRef<'input'> & { size?: number }
>(function MobileColorInput({ size = 52, style, ...props }, ref) {
  const { border, surface } = useAdminTheme();

  return (
    <input
      ref={ref}
      type="color"
      {...props}
      style={{
        width: size,
        height: size,
        borderRadius: 12,
        border: `1px solid ${border}`,
        background: surface,
        padding: 0,
        ...style,
      }}
    />
  );
});

export const MobileFileInput = React.forwardRef<HTMLInputElement, React.ComponentPropsWithoutRef<'input'>>(
  function MobileFileInput({ style, ...props }, ref) {
    return (
      <input
        ref={ref}
        type="file"
        {...props}
        style={{
          display: 'none',
          ...style,
        }}
      />
    );
  },
);

export const MobileDateTimeInput = React.forwardRef<
  HTMLInputElement,
  React.ComponentPropsWithoutRef<'input'> & ControlProps
>(function MobileDateTimeInput({ hasError = false, style, ...props }, ref) {
  const { border, surface, text, primary, danger } = useAdminTheme();
  const ringColor = hasError ? withAlpha(danger, 0.18) : withAlpha(primary, 0.18);
  const borderColor = hasError ? danger : border;

  return (
    <input
      ref={ref}
      type="datetime-local"
      {...props}
      style={{
        width: '100%',
        height: 44,
        padding: '0 12px',
        borderRadius: 12,
        borderWidth: 1,
        borderStyle: 'solid',
        borderColor,
        backgroundColor: surface,
        color: text,
        fontSize: 14,
        outline: 'none',
        boxShadow: `0 0 0 0 ${ringColor}`,
        ...style,
      }}
      onFocus={(event) => {
        event.currentTarget.style.boxShadow = `0 0 0 3px ${ringColor}`;
        props.onFocus?.(event);
      }}
      onBlur={(event) => {
        event.currentTarget.style.boxShadow = `0 0 0 0 ${ringColor}`;
        props.onBlur?.(event);
      }}
    />
  );
});

export const MobileDateInput = React.forwardRef<
  HTMLInputElement,
  React.ComponentPropsWithoutRef<'input'> & ControlProps
>(function MobileDateInput({ hasError = false, style, ...props }, ref) {
  const { border, surface, text, primary, danger } = useAdminTheme();
  const ringColor = hasError ? withAlpha(danger, 0.18) : withAlpha(primary, 0.18);
  const borderColor = hasError ? danger : border;

  return (
    <input
      ref={ref}
      type="date"
      {...props}
      style={{
        width: '100%',
        height: 44,
        padding: '0 12px',
        borderRadius: 12,
        borderWidth: 1,
        borderStyle: 'solid',
        borderColor,
        backgroundColor: surface,
        color: text,
        fontSize: 14,
        outline: 'none',
        boxShadow: `0 0 0 0 ${ringColor}`,
        ...style,
      }}
      onFocus={(event) => {
        event.currentTarget.style.boxShadow = `0 0 0 3px ${ringColor}`;
        props.onFocus?.(event);
      }}
      onBlur={(event) => {
        event.currentTarget.style.boxShadow = `0 0 0 0 ${ringColor}`;
        props.onBlur?.(event);
      }}
    />
  );
});

export const MobileInput = React.forwardRef<HTMLInputElement, React.ComponentPropsWithoutRef<'input'> & ControlProps>(
  function MobileInput({ hasError = false, compact = false, style, onChange, type, ...props }, ref) {
    const { border, surface, text, primary, danger } = useAdminTheme();
    const borderColor = hasError ? danger : border;
    const ringColor = hasError ? withAlpha(danger, 0.18) : withAlpha(primary, 0.18);
    const isPassword = type === 'password';

    return (
      <Input
        ref={ref as React.Ref<any>}
        {...props}
        {...({ type } as any)}
        secureTextEntry={isPassword}
        onChangeText={(value) => {
          onChange?.({ target: { value } } as React.ChangeEvent<HTMLInputElement>);
        }}
        size={compact ? '$3' : '$4'}
        height={compact ? 36 : 44}
        paddingHorizontal="$3"
        borderRadius={12}
        width="100%"
        fontSize={compact ? 13 : 14}
        backgroundColor={surface}
        color={text}
        borderColor={borderColor}
        focusStyle={{
          borderColor: hasError ? danger : primary,
          boxShadow: `0 0 0 3px ${ringColor}`,
        } as any}
        hoverStyle={{
          borderColor,
        } as any}
        style={style as any}
      />
    );
  },
);

export const MobileTextArea = React.forwardRef<
  HTMLTextAreaElement,
  React.ComponentPropsWithoutRef<'textarea'> & ControlProps
>(function MobileTextArea({ hasError = false, compact = false, style, onChange, ...props }, ref) {
  const { border, surface, text, primary, danger } = useAdminTheme();
  const borderColor = hasError ? danger : border;
  const ringColor = hasError ? withAlpha(danger, 0.18) : withAlpha(primary, 0.18);

  return (
    <TextArea
      ref={ref as React.Ref<any>}
      {...props}
      {...({ minHeight: compact ? 72 : 96 } as any)}
      onChangeText={(value) => {
        onChange?.({ target: { value } } as React.ChangeEvent<HTMLTextAreaElement>);
      }}
      size={compact ? '$3' : '$4'}
      borderRadius={12}
      padding="$3"
      width="100%"
      fontSize={compact ? 13 : 14}
      backgroundColor={surface}
      color={text}
      borderColor={borderColor}
      focusStyle={{
        borderColor: hasError ? danger : primary,
        boxShadow: `0 0 0 3px ${ringColor}`,
      } as any}
      hoverStyle={{
        borderColor,
      } as any}
      style={{ resize: 'vertical', ...style } as any}
    />
  );
});

export function MobileSelect({
  children,
  hasError = false,
  compact = false,
  containerStyle,
  style,
  ...props
}: MobileSelectProps) {
  const { border, surface, text, primary, danger, subtle } = useAdminTheme();
  const borderColor = hasError ? danger : border;
  const ringColor = hasError ? withAlpha(danger, 0.18) : withAlpha(primary, 0.18);
  const hasSizing =
    typeof containerStyle === 'object' &&
    containerStyle !== null &&
    ('width' in containerStyle ||
      'maxWidth' in containerStyle ||
      'minWidth' in containerStyle ||
      'flex' in containerStyle ||
      'flexGrow' in containerStyle);
  const options = React.Children.toArray(children).flatMap((child) => {
    if (!React.isValidElement(child)) return [];
    const { value, children: label, disabled } = child.props as {
      value?: string | number;
      children?: React.ReactNode;
      disabled?: boolean;
    };
    return [
      {
        value: value === undefined ? '' : String(value),
        label: label ?? '',
        disabled: Boolean(disabled),
      },
    ];
  });
  const emptyOption = options.find((option) => option.value === '');
  const selectValue = props.value === undefined ? undefined : String(props.value ?? '');
  const selectDefault = props.defaultValue === undefined ? undefined : String(props.defaultValue ?? '');

  return (
    <XStack position="relative" alignItems="center" width={hasSizing ? undefined : '100%'} style={containerStyle}>
      <Select
        value={selectValue}
        defaultValue={selectValue === undefined ? selectDefault : undefined}
        onValueChange={(next) => {
          props.onChange?.({ target: { value: next } } as React.ChangeEvent<HTMLSelectElement>);
        }}
        size={compact ? '$3' : '$4'}
      >
        <Select.Trigger
          width="100%"
          borderRadius={12}
          borderWidth={1}
          borderColor={borderColor as any}
          backgroundColor={surface as any}
          paddingVertical={compact ? 6 : 10}
          paddingHorizontal="$3"
          disabled={props.disabled}
          onFocus={props.onFocus as any}
          onBlur={props.onBlur as any}
          iconAfter={<ChevronDown size={16} color={subtle} />}
          focusStyle={{
            borderColor: (hasError ? danger : primary) as any,
            boxShadow: `0 0 0 3px ${ringColor}`,
          }}
          hoverStyle={{
            borderColor: borderColor as any,
          }}
          style={style as any}
        >
          <Select.Value placeholder={props.placeholder ?? (emptyOption?.label as any) ?? ''} {...({ color: text } as any)} />
        </Select.Trigger>
        <Select.Content
          zIndex={200000}
          {...({ borderRadius: 14 } as any)}
          borderWidth={1}
          borderColor={border}
          backgroundColor={surface as any}
        >
          <Select.Viewport {...({ padding: "$2" } as any)}>
            <Select.Group>
              {options.map((option, index) => (
                <Select.Item index={index} key={`${option.value}-${index}`} value={option.value} disabled={option.disabled}>
                  <Select.ItemText>{option.label}</Select.ItemText>
                </Select.Item>
              ))}
            </Select.Group>
          </Select.Viewport>
        </Select.Content>
      </Select>
      {props.name ? <input type="hidden" name={props.name} value={selectValue ?? selectDefault ?? ''} /> : null}
    </XStack>
  );
}
