import { TranslatedString } from "@gnu-taler/taler-util";
import { Fragment, h, VNode } from "preact";
import { useState } from "preact/hooks";
import {
  getValueFromPath,
  RecursivePartial,
  useForm,
} from "../../hooks/useForm.js";
import {
  SingleColumnFormSectionUI,
  useTranslationContext,
} from "../../index.browser.js";
import { UIFormProps } from "../FormProvider.js";
import { UIFormElementConfig } from "../forms-types.js";
import { LabelWithTooltipMaybeRequired } from "./InputLine.js";

export function noHandlerPropsAndNoContextForField(
  field: string | number | symbol,
): never {
  throw Error(
    `Field ${field.toString()} doesn't have handler and is not in a form provider context.`,
  );
}

type FormType = {};

function ArrayForm({
  fields,
  selected,
  onClose,
  onRemove,
  onConfirm,
  name,
}: {
  fields: UIFormElementConfig[];
  selected: Record<string, string | undefined> | undefined;
  onClose: () => void;
  onRemove: () => void;
  onConfirm: (r: RecursivePartial<FormType>) => void;
  name: string;
}): VNode {
  const { i18n } = useTranslationContext();
  const form = useForm<FormType>(
    {
      type: "single-column",
      fields,
    },
    selected ?? {},
  );

  return (
    <div class="px-4 py-6">
      <div class="grid grid-cols-1 gap-y-8 ">
        <SingleColumnFormSectionUI
          fields={fields}
          model={form.model}
          name={name}
        />
      </div>
      {/* <pre>{JSON.stringify(form.status, undefined, 2)}</pre> */}

      <div class="flex items-center justify-end gap-x-6 mt-4">
        <button
          type="button"
          onClick={onClose}
          class="block px-3 py-2 text-sm font-semibold leading-6 text-gray-900"
        >
          <i18n.Translate>Cancel</i18n.Translate>
        </button>

        <button
          type="button"
          disabled={selected === undefined}
          onClick={() => {
            onRemove();
          }}
          // onClick={() => {
          //   const newValue = [...list];
          //   newValue.splice(selectedIndex, 1);
          //   onChange(newValue as any);
          //   // setSelectedIndex(undefined);
          // }}
          class="block rounded-md bg-red-600 px-3 py-2 text-center text-sm  text-white shadow-sm hover:bg-red-500 disabled:cursor-not-allowed disabled:bg-gray-50 disabled:text-gray-500 disabled:ring-gray-200"
        >
          <i18n.Translate>Remove</i18n.Translate>
        </button>

        <button
          type="button"
          disabled={form.status.status !== "ok"}
          onClick={() => {
            onConfirm(form.status.result);
          }}
          class="block rounded-md bg-indigo-600 px-3 py-2 text-center text-sm  text-white shadow-sm hover:bg-indigo-500 disabled:cursor-not-allowed disabled:bg-gray-50 disabled:text-gray-500 disabled:ring-gray-200"
        >
          <i18n.Translate>Confirm</i18n.Translate>
        </button>
      </div>
    </div>
  );
}

export function InputArray(
  props: {
    fields: UIFormElementConfig[];
    labelField: string;
  } & UIFormProps<string[]>,
): VNode {
  const { fields, labelField, label, required, tooltip, hidden, help } = props;
  const { i18n } = useTranslationContext();

  const { value, onChange, error } =
    props.handler ?? noHandlerPropsAndNoContextForField(props.name);
  const [dirty, setDirty] = useState<boolean>(); // FIXME: dirty state should come from handler

  //@ts-ignore
  const list = (value ?? []) as Array<Record<string, string>>;
  const [selectedIndex, setSelectedIndex] = useState<number | undefined>(
    undefined,
  );

  if (hidden) {
    return <Fragment />;
  }
  const selected =
    selectedIndex === undefined ? undefined : list[selectedIndex];

  return (
    <div class="sm:col-span-6">
      <LabelWithTooltipMaybeRequired
        label={label}
        required={required}
        tooltip={tooltip}
        name={String(props.name)}
      />
      {help && (
        <p class="mt-2 text-sm text-gray-500" id="email-description">
          {help}
        </p>
      )}
      {dirty !== undefined && error && (
        <p class="mt-2 text-sm text-red-600" id="email-error">
          {error}
        </p>
      )}

      <div class="overflow-visible ring-1 ring-gray-900/5 rounded-xl p-4">
        <div class="-space-y-px rounded-md bg-white ">
          {list.map((v, idx) => {
            const labelValue =
              getValueFromPath(v, labelField.split(".")) ??
              `<<Item ${idx + 1}>>`;
            const label = Array.isArray(labelValue)
              ? labelValue.join(", ")
              : labelValue;
            return (
              <Option
                label={label as TranslatedString}
                key={idx}
                isSelected={selectedIndex === idx}
                isLast={idx === list.length - 1}
                disabled={selectedIndex !== undefined && selectedIndex !== idx}
                isFirst={idx === 0}
                onClick={() => {
                  setSelectedIndex(selectedIndex === idx ? undefined : idx);
                }}
              />
            );
          })}
          {!props.disabled && (
            <div class="pt-2">
              <Option
                label={i18n.str`Add new...`}
                isSelected={selectedIndex === list.length}
                isLast
                isFirst
                disabled={
                  selectedIndex !== undefined && selectedIndex !== list.length
                }
                onClick={() => {
                  setSelectedIndex(
                    selectedIndex === list.length ? undefined : list.length,
                  );
                }}
              />
            </div>
          )}
        </div>
        {selectedIndex !== undefined && (
          <ArrayForm
            name={props.name as string}
            fields={fields}
            onRemove={() => {
              const newValue = [...list];
              newValue.splice(selectedIndex, 1);
              onChange(newValue as any);
              setDirty(true);
              setSelectedIndex(undefined);
            }}
            onClose={() => {
              setDirty(true);
              setSelectedIndex(undefined);
            }}
            onConfirm={(value) => {
              const newValue = [...list];
              newValue.splice(selectedIndex, 1, value);
              onChange(newValue as any);
              setDirty(true);
              setSelectedIndex(undefined);
            }}
            selected={selected}
          />
        )}
      </div>
    </div>
  );
}

function Option({
  label,
  disabled,
  isFirst,
  isLast,
  isSelected,
  onClick,
}: {
  label: TranslatedString;
  isFirst?: boolean;
  isLast?: boolean;
  isSelected?: boolean;
  disabled?: boolean;
  onClick: () => void;
}): VNode {
  let clazz = "relative flex border p-4 focus:outline-none disabled:text-grey";
  if (isFirst) {
    clazz += " rounded-tl-md rounded-tr-md ";
  }
  if (isLast) {
    clazz += " rounded-bl-md rounded-br-md ";
  }
  if (isSelected) {
    clazz += " z-10 border-indigo-200 bg-indigo-50 ";
  } else {
    clazz += " border-gray-200";
  }
  if (disabled) {
    clazz +=
      " cursor-not-allowed bg-gray-50 text-gray-500 ring-gray-200  text-gray";
  } else {
    clazz += " cursor-pointer";
  }
  return (
    <label class={clazz}>
      <input
        type="radio"
        name="privacy-setting"
        checked={isSelected}
        disabled={disabled}
        onClick={onClick}
        class="mt-0.5 h-4 w-4 shrink-0 text-indigo-600 disabled:cursor-not-allowed disabled:bg-gray-50 disabled:text-gray-500 disabled:ring-gray-200  focus:ring-indigo-600"
        aria-labelledby="privacy-setting-0-label"
        aria-describedby="privacy-setting-0-description"
      />
      <span class="ml-3 flex flex-col">
        <span
          id="privacy-setting-0-label"
          disabled
          class="block text-sm font-medium"
        >
          {label}
        </span>
        {/* <!-- Checked: "text-indigo-700", Not Checked: "text-gray-500" --> */}
        {/* <span
        id="privacy-setting-0-description"
        class="block text-sm"
      >
        This project would be available to anyone who has the link
      </span> */}
      </span>
    </label>
  );
}
