import { Controller, type Path, type UseFormReturn } from "react-hook-form";
import { useTranslation } from "react-i18next";

import type { components } from "../api/schema";
import { useAuthorities, useTerms } from "../api/queries";
import { useConfig } from "../config/config-context";
import { useLang } from "../lib/use-lang";
import { labelText } from "../lib/labels";
import { OptionsCombobox } from "./options-combobox";
import { Checkbox } from "@/components/ui/checkbox";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";

type FieldDefinitionView = components["schemas"]["FieldDefinitionView"];

type FieldForm<TValues extends { fields: Record<string, unknown> }> = UseFormReturn<TValues>;

function fieldPath<TValues extends { fields: Record<string, unknown> }>(
  key: string,
): Path<TValues> {
  return `fields.${key}` as Path<TValues>;
}

export function FieldInput<TValues extends { fields: Record<string, unknown> }>({
  definition,
  form,
}: {
  definition: FieldDefinitionView;
  form: FieldForm<TValues>;
}) {
  const { t } = useTranslation();
  const { default_language } = useConfig();
  const lang = useLang();
  const label = labelText(definition.labels, lang);
  const name = fieldPath<TValues>(definition.key);
  const placeholder = t("form.selectPlaceholder");

  switch (definition.data_type) {
    case "integer":
      return (
        <div className="space-y-1">
          <Label htmlFor={definition.key}>{label}</Label>

          <Input
            id={definition.key}
            type="number"
            {...form.register(name, {
              valueAsNumber: true,
              required: definition.required,
            })}
          />
        </div>
      );

    case "date":
      return (
        <div className="space-y-1">
          <Label htmlFor={definition.key}>{label}</Label>

          <Input
            id={definition.key}
            type="date"
            {...form.register(name, { required: definition.required })}
          />
        </div>
      );

    case "boolean":
      // A checkbox always has a boolean value, so `required` is a no-op here.
      return (
        <div className="flex items-center gap-2">
          <Controller
            control={form.control}
            name={name}
            render={({ field }) => (
              <Checkbox
                id={definition.key}
                checked={!!field.value}
                onCheckedChange={(checked) => field.onChange(checked === true)}
              />
            )}
          />

          <Label htmlFor={definition.key}>{label}</Label>
        </div>
      );

    case "localized_text":
      return (
        <div className="space-y-1">
          <Label htmlFor={definition.key}>{label}</Label>
          <Input
            id={definition.key}
            {...form.register(fieldPath<TValues>(`${definition.key}.${default_language}`), {
              required: definition.required,
            })}
          />
        </div>
      );

    case "term":
      return (
        <TermField
          definition={definition}
          form={form}
          label={label}
          lang={lang}
          placeholder={placeholder}
        />
      );

    case "authority":
      return (
        <AuthorityField
          definition={definition}
          form={form}
          label={label}
          lang={lang}
          placeholder={placeholder}
        />
      );

    case "text":
    default:
      return (
        <div className="space-y-1">
          <Label htmlFor={definition.key}>{label}</Label>

          <Input
            id={definition.key}
            {...form.register(name, { required: definition.required })}
          />
        </div>
      );
  }
}

function TermField<TValues extends { fields: Record<string, unknown> }>({
  definition,
  form,
  label,
  lang,
  placeholder,
}: {
  definition: FieldDefinitionView;
  form: FieldForm<TValues>;
  label: string;
  lang: string;
  placeholder: string;
}) {
  const { data: terms } = useTerms(definition.vocabulary_id);

  return (
    <div className="space-y-1">
      <Label htmlFor={definition.key}>{label}</Label>

      <Controller
        control={form.control}
        name={fieldPath<TValues>(definition.key)}
        rules={{ required: definition.required }}
        render={({ field }) => (
          <OptionsCombobox
            id={definition.key}
            value={(field.value as string) ?? ""}
            onChange={field.onChange}
            options={terms ?? []}
            lang={lang}
            placeholder={placeholder}
          />
        )}
      />
    </div>
  );
}

function AuthorityField<TValues extends { fields: Record<string, unknown> }>({
  definition,
  form,
  label,
  lang,
  placeholder,
}: {
  definition: FieldDefinitionView;
  form: FieldForm<TValues>;
  label: string;
  lang: string;
  placeholder: string;
}) {
  const { data: authorities } = useAuthorities(definition.authority_kind);

  return (
    <div className="space-y-1">
      <Label htmlFor={definition.key}>{label}</Label>

      <Controller
        control={form.control}
        name={fieldPath<TValues>(definition.key)}
        rules={{ required: definition.required }}
        render={({ field }) => (
          <OptionsCombobox
            id={definition.key}
            value={(field.value as string) ?? ""}
            onChange={field.onChange}
            options={authorities ?? []}
            lang={lang}
            placeholder={placeholder}
          />
        )}
      />
    </div>
  );
}
