import { TranslatedString } from "@gnu-taler/taler-util";
import { ComponentChildren, Fragment, VNode, h } from "preact";
import { useEffect, useRef } from "preact/hooks";
import { composeRef, saveRef } from "../../components/utils.js";
import { Addon, UIFormProps } from "../FormProvider.js";
import { noHandlerPropsAndNoContextForField } from "./InputArray.js";

//@ts-ignore
const TooltipIcon = (
  <svg
    class="w-5 h-5"
    xmlns="http://www.w3.org/2000/svg"
    viewBox="0 0 20 20"
    fill="currentColor"
  >
    <path
      fill-rule="evenodd"
      d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-8-3a1 1 0 00-.867.5 1 1 0 11-1.731-1A3 3 0 0113 8a3.001 3.001 0 01-2 2.83V11a1 1 0 11-2 0v-1a1 1 0 011-1 1 1 0 100-2zm0 8a1 1 0 100-2 1 1 0 000 2z"
      clip-rule="evenodd"
    />
  </svg>
);

export function LabelWithTooltipMaybeRequired({
  label,
  required,
  tooltip,
  name,
}: {
  label: TranslatedString;
  required?: boolean;
  tooltip?: TranslatedString;
  name?: string;
}): VNode {
  const Label = (
    <div class="flex justify-between">
      <label
        for={name}
        class="block text-sm font-medium leading-6 text-gray-900"
      >
        {label}
      </label>
    </div>
  );
  const WithTooltip = tooltip ? (
    <div class="relative flex flex-grow items-stretch focus-within:z-10">
      {Label}
      <span class="relative flex items-center group pl-2">
        {TooltipIcon}
        <div class="absolute bottom-0 -ml-10 hidden flex-col items-center mb-6 group-hover:flex w-28">
          <div class="relative z-10 p-2 text-xs leading-none text-white whitespace-no-wrap bg-black shadow-lg">
            {tooltip}
          </div>
          <div class="w-3 h-3 -mt-2  rotate-45 bg-black"></div>
        </div>
      </span>
    </div>
  ) : (
    Label
  );
  if (required) {
    return (
      <div class="flex justify-between w-fit">
        {WithTooltip}
        <span class="text-sm leading-6 text-red-600 pl-2">*</span>
      </div>
    );
  }
  return WithTooltip;
}

export function RenderAddon({
  disabled,
  addon,
  reverse,
}: {
  disabled?: boolean;
  reverse?: boolean;
  addon: Addon;
}): VNode {
  switch (addon.type) {
    case "text": {
      return (
        <span class="inline-flex items-center data-[right=true]:rounded-r-md data-[left=true]:rounded-l-md border border-r-0 border-gray-300 px-3 text-gray-500 sm:text-sm">
          {addon.text}
        </span>
      );
    }
    case "icon": {
      return (
        <div class="pointer-events-none absolute inset-y-0 left-0 flex items-center pl-3">
          {addon.icon}
        </div>
      );
    }
    case "button": {
      return (
        <button
          type="button"
          disabled={disabled}
          onClick={addon.onClick}
          data-left={!reverse}
          data-right={reverse}
          class="relative -ml-px inline-flex items-center gap-x-1.5 data-[right=true]:rounded-r-md data-[left=true]:rounded-l-md px-3 py-2 text-sm font-semibold text-gray-900 ring-1 ring-inset ring-gray-300 hover:bg-gray-50 disabled:bg-gray-50 disabled:cursor-not-allowed"
        >
          {addon.children}
        </button>
      );
    }
  }
}

/**
 * FIXME: Document what this is!
 */
export function InputWrapper<T>({
  children,
  label,
  tooltip,
  before,
  after,
  help,
  error,
  disabled,
  required,
  name,
}: {
  error?: string;
  disabled: boolean;
  children: ComponentChildren;
} & UIFormProps<T>): VNode {
  return (
    <div class="sm:col-span-6 ">
      <LabelWithTooltipMaybeRequired
        label={label}
        required={required}
        tooltip={tooltip}
        name={name as string}
      />
      <div class="relative mt-2 flex rounded-md shadow-sm">
        {before && <RenderAddon disabled={disabled} addon={before} />}

        {children}

        {after && <RenderAddon disabled={disabled} addon={after} reverse />}
      </div>
      {error && (
        <p class="mt-2 text-sm text-red-600" id="email-error">
          {error}
        </p>
      )}
      {help && (
        <p class="mt-2 text-sm text-gray-500" id="email-description">
          {help}
        </p>
      )}
    </div>
  );
}

function defaultToString(v: unknown) {
  return v === undefined ? "" : typeof v !== "object" ? String(v) : "";
}
function defaultFromString(v: string) {
  return v;
}

type InputType = "text" | "text-area" | "password" | "email" | "number";

export function InputLine(
  props: { type: InputType; defaultValue?: string } & UIFormProps<string>,
): VNode {
  const {
    name,
    placeholder,
    before,
    after,
    converter,
    type,
    disabled,
    hidden,
  } = props;
  const input = useRef<HTMLTextAreaElement | HTMLInputElement>();

  const { value, onChange, error } =
    props.handler ?? noHandlerPropsAndNoContextForField(props.name);

  const fromString: (s: string) => any =
    converter?.fromStringUI ?? defaultFromString;
  const toString: (s: any) => string = converter?.toStringUI ?? defaultToString;

  useEffect(() => {
    if (!input.current) return;
    if (input.current === document.activeElement) return;
    input.current.value = !value ? "" : toString(value);
  }, [value]);

  // useHiddenHandler(name as string, hidden ?? false, value, onChange);
  if (hidden) {
    return <Fragment />;
  }

  let clazz =
    "block w-full rounded-md border-0 py-1.5 shadow-sm ring-1 ring-inset focus:ring-2 focus:ring-inset sm:text-sm sm:leading-6 disabled:cursor-not-allowed disabled:bg-gray-50 disabled:text-gray-500 disabled:ring-gray-200";
  if (before) {
    switch (before.type) {
      case "icon": {
        clazz += " pl-10";
        break;
      }
      case "button": {
        clazz += " rounded-none rounded-r-md ";
        break;
      }
      case "text": {
        clazz += " min-w-0 flex-1 rounded-r-md rounded-none ";
        break;
      }
    }
  }
  if (after) {
    switch (after.type) {
      case "icon": {
        clazz += " pr-10";
        break;
      }
      case "button": {
        clazz += " rounded-none rounded-l-md";
        break;
      }
      case "text": {
        clazz += " min-w-0 flex-1 rounded-l-md rounded-none ";
        break;
      }
    }
  }
  const showError = value !== undefined && error;
  if (showError) {
    clazz +=
      " text-red-900 ring-red-300  placeholder:text-red-300 focus:ring-red-500";
  } else {
    clazz +=
      " text-gray-900 ring-gray-300 placeholder:text-gray-400 focus:ring-indigo-600";
  }

  if (type === "text-area") {
    return (
      <InputWrapper
        {...props}
        help={props.help}
        disabled={disabled ?? false}
        error={showError ? error : undefined}
      >
        <textarea
          rows={4}
          ref={composeRef(saveRef(input))}
          // ref={composeRef(saveRef(input), doAutoFocus)} FIXME: enable autofocus when form has focus
          name={String(name)}
          onChange={(e) => {
            onChange(fromString(e.currentTarget.value));
          }}
          defaultValue={props.defaultValue}
          placeholder={placeholder ? placeholder : undefined}
          // value={toString(value) ?? ""}
          // defaultValue={toString(value)}
          disabled={disabled ?? false}
          aria-invalid={showError}
          // aria-describedby="email-error"
          class={clazz}
        />
      </InputWrapper>
    );
  }

  return (
    <InputWrapper
      {...props}
      help={props.help}
      disabled={disabled ?? false}
      error={showError ? error : undefined}
    >
      <input
        name={String(name)}
        ref={composeRef(saveRef(input))}
        // ref={composeRef(saveRef(input), doAutoFocus)} FIXME: enable autofocus when form has focus
        type={type}
        onChange={(e) => {
          onChange(fromString(e.currentTarget.value));
        }}
        placeholder={placeholder ? placeholder : undefined}
        // value={toString(value) ?? ""}
        // onBlur={() => {
        //   onChange(fromString(value as any));
        // }}
        defaultValue={toString(value)}
        disabled={disabled ?? false}
        aria-invalid={showError}
        // aria-describedby="email-error"
        class={clazz}
      />
    </InputWrapper>
  );
}
