import { VNode } from "preact";
import { Caption } from "./Caption.js";
import { ExternalLink } from "./fields/ExternalLink.js";
import { InputAbsoluteTime } from "./fields/InputAbsoluteTime.js";
import { InputAmount } from "./fields/InputAmount.js";
import { InputArray } from "./fields/InputArray.js";
import { InputChoiceHorizontal } from "./fields/InputChoiceHorizontal.js";
import { InputChoiceStacked } from "./fields/InputChoiceStacked.js";
import { InputDownloadLink } from "./fields/InputDownloadLink.js";
import { InputDrilldown } from "./fields/InputDrilldown.js";
import { InputDuration } from "./fields/InputDuration.js";
import { InputDurationText } from "./fields/InputDurationText.js";
import { InputFile } from "./fields/InputFile.js";
import { InputInteger } from "./fields/InputInteger.js";
import { InputIsoDate } from "./fields/InputIsoDate.js";
import { InputSecret } from "./fields/InputSecret.js";
import { InputSelectMultiple } from "./fields/InputSelectMultiple.js";
import { InputSelectOne } from "./fields/InputSelectOne.js";
import { InputText } from "./fields/InputText.js";
import { InputTextArea } from "./fields/InputTextArea.js";
import { InputToggle } from "./fields/InputToggle.js";
import { Group } from "./Group.js";
import { HtmlIframe } from "./HtmlIframe.js";

/**
 * Constrain the type with the ui props
 */
type FieldType<T extends object = any, K extends keyof T = any> = {
  group: Parameters<typeof Group>[0];
  caption: Parameters<typeof Caption>[0];
  "download-link": Parameters<typeof InputDownloadLink>[0];
  "external-link": Parameters<typeof ExternalLink>[0];
  htmlIframe: Parameters<typeof HtmlIframe>[0];
  array: Parameters<typeof InputArray>[0];
  file: Parameters<typeof InputFile>[0];
  selectOne: Parameters<typeof InputSelectOne<T[K]>>[0];
  selectMultiple: Parameters<typeof InputSelectMultiple>[0];
  text: Parameters<typeof InputText>[0];
  textArea: Parameters<typeof InputTextArea>[0];
  choiceStacked: Parameters<typeof InputChoiceStacked<T[K]>>[0];
  drilldown: Parameters<typeof InputDrilldown>[0];
  choiceHorizontal: Parameters<typeof InputChoiceHorizontal<T[K]>>[0];
  absoluteTimeText: Parameters<typeof InputAbsoluteTime>[0];
  isoDateText: Parameters<typeof InputIsoDate>[0];
  integer: Parameters<typeof InputInteger>[0];
  secret: Parameters<typeof InputSecret>[0];
  toggle: Parameters<typeof InputToggle>[0];
  amount: Parameters<typeof InputAmount>[0];
  duration: Parameters<typeof InputDuration>[0];
  durationText: Parameters<typeof InputDurationText>[0];
};

/**
 * List all the form fields so typescript can type-check the form instance
 */
export type UIFormField =
  | { type: "group"; properties: FieldType["group"] }
  | { type: "caption"; properties: FieldType["caption"] }
  | { type: "download-link"; properties: FieldType["download-link"] }
  | { type: "external-link"; properties: FieldType["external-link"] }
  | { type: "htmlIframe"; properties: FieldType["htmlIframe"] }
  | { type: "array"; properties: FieldType["array"] }
  | { type: "file"; properties: FieldType["file"] }
  | { type: "amount"; properties: FieldType["amount"] }
  | { type: "selectOne"; properties: FieldType["selectOne"] }
  | {
      type: "selectMultiple";
      properties: FieldType["selectMultiple"];
    }
  | { type: "text"; properties: FieldType["text"] }
  | { type: "textArea"; properties: FieldType["textArea"] }
  | {
      type: "choiceStacked";
      properties: FieldType["choiceStacked"];
    }
  | {
      type: "choiceHorizontal";
      properties: FieldType["choiceHorizontal"];
    }
  | {
      type: "drilldown";
      properties: FieldType["drilldown"];
    }
  | { type: "integer"; properties: FieldType["integer"] }
  | { type: "secret"; properties: FieldType["secret"] }
  | { type: "toggle"; properties: FieldType["toggle"] }
  | {
      type: "absoluteTimeText";
      properties: FieldType["absoluteTimeText"];
    }
  | {
      type: "isoDateText";
      properties: FieldType["isoDateText"];
    }
  | {
      type: "duration";
      properties: FieldType["duration"];
    }
  | {
      type: "durationText";
      properties: FieldType["durationText"];
    };

export type FieldComponentFunction<key extends keyof FieldType> = (
  props: FieldType[key],
) => VNode;

type UIFormFieldMap = {
  [key in keyof FieldType]: FieldComponentFunction<key>;
};

/**
 * Maps input type with component implementation
 */
export const UIFormConfiguration: UIFormFieldMap = {
  group: Group,
  "download-link": InputDownloadLink,
  "external-link": ExternalLink,
  caption: Caption,
  htmlIframe: HtmlIframe,
  //@ts-ignore
  array: InputArray,
  text: InputText,
  //@ts-ignore
  file: InputFile,
  textArea: InputTextArea,
  //@ts-ignore
  absoluteTimeText: InputAbsoluteTime,
  //@ts-ignore
  isoDateText: InputIsoDate,
  //@ts-ignore
  choiceStacked: InputChoiceStacked,
  //@ts-ignore
  choiceHorizontal: InputChoiceHorizontal,
  integer: InputInteger,
  secret: InputSecret,
  //@ts-ignore
  selectOne: InputSelectOne,
  //@ts-ignore
  selectMultiple: InputSelectMultiple,
  //@ts-ignore
  toggle: InputToggle,
  //@ts-ignore
  amount: InputAmount,
  drilldown: InputDrilldown,
  duration: InputDuration,
  durationText: InputDurationText,
};
