import { useFieldContext, useFormContext } from '@hooks/use-app-form';
import { useStore } from '@tanstack/react-form';
import { Button, buttonVariants } from '@ui/button';
import { Field, FieldError, FieldLabel } from '@ui/field';
import { Input } from '@ui/input';
import * as ShadcnSelect from '@ui/select';
import {
  SelectHouse as SelectHouseUI,
  SelectUser as SelectUserUI,
} from '@ui/select-user';
import { Textarea } from '@ui/textarea';
import { type VariantProps } from 'class-variance-authority';
import { Spinner } from '../ui/spinner';
import { TagInput as TagInputUI } from '../ui/tag-input';

export function SubscribeButton({
  label,
  variant = 'default',
  disabled = false,
}: {
  label: string;
  disabled?: boolean;
} & VariantProps<typeof buttonVariants>) {
  const form = useFormContext();
  return (
    <form.Subscribe selector={(state) => state.isSubmitting}>
      {(isSubmitting) => {
        return (
          <Button
            type="submit"
            disabled={isSubmitting || disabled}
            variant={variant}
          >
            {(isSubmitting || disabled) && <Spinner data-icon="inline-start" />}
            {label}
          </Button>
        );
      }}
    </form.Subscribe>
  );
}

export function HiddenField() {
  const field = useFieldContext<string>();
  const errors = useStore(field.store, (state) => state.meta.errors);
  const isInvalid = field.state.meta.isTouched && !field.state.meta.isValid;

  return (
    <Field data-invalid={isInvalid}>
      <Input
        id={field.name}
        name={field.name}
        value={field.state.value}
        aria-invalid={isInvalid}
        type="hidden"
      />
      {isInvalid && <FieldError errors={errors} />}
    </Field>
  );
}

export function TextField({
  label,
  placeholder,
  type = 'text',
}: {
  label: string;
  placeholder?: string;
  type?: string;
}) {
  const field = useFieldContext<string>();
  const errors = useStore(field.store, (state) => state.meta.errors);
  const isInvalid = field.state.meta.isTouched && !field.state.meta.isValid;

  return (
    <Field data-invalid={isInvalid}>
      <FieldLabel htmlFor={field.name}>{label}:</FieldLabel>
      <Input
        id={field.name}
        name={field.name}
        value={field.state.value}
        onBlur={field.handleBlur}
        placeholder={placeholder}
        onChange={(e) => field.handleChange(e.target.value)}
        aria-invalid={isInvalid}
        type={type}
      />
      {isInvalid && <FieldError errors={errors} />}
    </Field>
  );
}

export function FileField({
  label,
  className,
  ...props
}: {
  label: string;
  className?: string;
} & React.ComponentProps<'input'>) {
  const field = useFieldContext<string>();
  const errors = useStore(field.store, (state) => state.meta.errors);
  const isInvalid = field.state.meta.isTouched && !field.state.meta.isValid;

  return (
    <Field data-invalid={isInvalid} className={className}>
      <FieldLabel htmlFor={field.name}>{label}:</FieldLabel>
      <Input
        type="file"
        id={field.name}
        name={field.name}
        aria-invalid={isInvalid}
        {...props}
      />
      {isInvalid && <FieldError errors={errors} />}
    </Field>
  );
}

export function TextArea({
  label,
  rows = 4,
}: {
  label: string;
  rows?: number;
}) {
  const field = useFieldContext<string>();
  const errors = useStore(field.store, (state) => state.meta.errors);
  const isInvalid = field.state.meta.isTouched && !field.state.meta.isValid;

  return (
    <Field data-invalid={isInvalid} className="col-span-2">
      <FieldLabel htmlFor={field.name}>{label}:</FieldLabel>
      <Textarea
        id={field.name}
        name={field.name}
        value={field.state.value}
        onBlur={field.handleBlur}
        onChange={(e) => field.handleChange(e.target.value)}
        aria-invalid={isInvalid}
        rows={rows}
      />
      {isInvalid && <FieldError errors={errors} />}
    </Field>
  );
}

export function Select({
  label,
  values,
  placeholder,
  // isRole = false,
}: {
  label: string;
  values: Array<{ label: string; value: string }>;
  placeholder?: string;
}) {
  const field = useFieldContext<string>();
  const errors = useStore(field.store, (state) => state.meta.errors);
  const isInvalid = field.state.meta.isTouched && !field.state.meta.isValid;

  return (
    <Field data-invalid={isInvalid} className="col-span-2">
      <FieldLabel htmlFor={field.name}>{label}:</FieldLabel>
      <ShadcnSelect.Select
        name={field.name}
        value={String(field.state.value)}
        onValueChange={(value) => field.handleChange(value)}
      >
        <ShadcnSelect.SelectTrigger aria-invalid={isInvalid}>
          <ShadcnSelect.SelectValue placeholder={placeholder} />
        </ShadcnSelect.SelectTrigger>
        <ShadcnSelect.SelectContent>
          <ShadcnSelect.SelectGroup>
            <ShadcnSelect.SelectLabel>{label}</ShadcnSelect.SelectLabel>
            {values.map((value) => (
              <ShadcnSelect.SelectItem key={value.value} value={value.value}>
                {value.label}
              </ShadcnSelect.SelectItem>
            ))}
          </ShadcnSelect.SelectGroup>
        </ShadcnSelect.SelectContent>
      </ShadcnSelect.Select>
      {isInvalid && <FieldError errors={errors} />}
    </Field>
  );
}

export function SelectNumber({
  label,
  values,
  placeholder,
}: {
  label: string;
  values: Array<{ label: string; value: string }>;
  placeholder?: string;
}) {
  const field = useFieldContext<number>();
  const errors = useStore(field.store, (state) => state.meta.errors);
  const isInvalid = field.state.meta.isTouched && !field.state.meta.isValid;

  return (
    <Field data-invalid={isInvalid} className="col-span-2">
      <FieldLabel htmlFor={field.name}>{label}:</FieldLabel>
      <ShadcnSelect.Select
        name={field.name}
        value={field.state.value === 0 ? String('') : String(field.state.value)}
        onValueChange={(value) => field.handleChange(Number(value))}
      >
        <ShadcnSelect.SelectTrigger aria-invalid={isInvalid}>
          <ShadcnSelect.SelectValue placeholder={placeholder} />
        </ShadcnSelect.SelectTrigger>
        <ShadcnSelect.SelectContent>
          <ShadcnSelect.SelectGroup>
            <ShadcnSelect.SelectLabel>{label}</ShadcnSelect.SelectLabel>
            {values.map((value) => (
              <ShadcnSelect.SelectItem key={value.value} value={value.value}>
                {value.label}
              </ShadcnSelect.SelectItem>
            ))}
          </ShadcnSelect.SelectGroup>
        </ShadcnSelect.SelectContent>
      </ShadcnSelect.Select>
      {isInvalid && <FieldError errors={errors} />}
    </Field>
  );
}

export function SelectUser({
  label,
  values,
  placeholder,
  keyword,
  onKeywordChange,
  searchPlaceholder = 'Tìm theo tên hoặc email...',
  selectKey = 'id',
}: {
  label: string;
  values: Array<{
    id: string;
    name: string;
    email: string;
    image: string | null;
    role: string | null;
  }>;
  placeholder?: string;
  /** Khi truyền cùng onKeywordChange: tìm kiếm theo API (keyword gửi lên server) */
  keyword?: string;
  onKeywordChange?: (value: string) => void;
  searchPlaceholder?: string;
  selectKey?: 'id' | 'email';
}) {
  const field = useFieldContext<string>();
  const errors = useStore(field.store, (state) => state.meta.errors);
  const isInvalid = field.state.meta.isTouched && !field.state.meta.isValid;

  return (
    <Field data-invalid={isInvalid} className="col-span-2">
      <FieldLabel htmlFor={field.name}>{label}:</FieldLabel>
      <SelectUserUI
        name={field.name}
        id={field.name}
        value={field.state.value}
        onValueChange={(userId) => field.handleChange(userId)}
        values={values}
        placeholder={placeholder}
        keyword={keyword}
        onKeywordChange={onKeywordChange}
        searchPlaceholder={searchPlaceholder}
        aria-invalid={isInvalid}
        selectKey={selectKey}
      />
      {isInvalid && <FieldError errors={errors} />}
    </Field>
  );
}

export function SelectHouse({
  label,
  values,
  placeholder,
  keyword,
  onKeywordChange,
  searchPlaceholder = 'Tìm theo tên...',
}: {
  label: string;
  values: Array<{
    id: string;
    name: string;
  }>;
  placeholder?: string;
  keyword?: string;
  onKeywordChange?: (value: string) => void;
  searchPlaceholder?: string;
}) {
  const field = useFieldContext<string>();
  const errors = useStore(field.store, (state) => state.meta.errors);
  const isInvalid = field.state.meta.isTouched && !field.state.meta.isValid;

  return (
    <Field data-invalid={isInvalid} className="col-span-2">
      <FieldLabel htmlFor={field.name}>{label}:</FieldLabel>
      <SelectHouseUI
        name={field.name}
        id={field.name}
        value={field.state.value}
        onValueChange={(id) => field.handleChange(id)}
        values={values}
        placeholder={placeholder}
        keyword={keyword}
        onKeywordChange={onKeywordChange}
        searchPlaceholder={searchPlaceholder}
        aria-invalid={isInvalid}
      />
      {isInvalid && <FieldError errors={errors} />}
    </Field>
  );
}

export function TagInput({
  label,
  placeholder,
  max = 10,
}: {
  label: string;
  placeholder?: string;
  max?: number;
}) {
  const field = useFieldContext<string[]>();
  const errors = useStore(field.store, (state) => state.meta.errors);
  const isInvalid = field.state.meta.isTouched && !field.state.meta.isValid;

  return (
    <Field data-invalid={isInvalid}>
      <FieldLabel htmlFor={field.name}>{label}:</FieldLabel>
      <TagInputUI
        id={field.name}
        name={field.name}
        value={field.state.value}
        onChange={(value) => field.handleChange(value)}
        maxTags={max}
        placeholder={placeholder}
        aria-invalid={isInvalid}
      />
      {isInvalid && <FieldError errors={errors} />}
    </Field>
  );
}
