"use client";

import cx from "classnames";
import dynamic from "next/dynamic";
import React from "react";

// Importing Autocomplete dynamically to avoid server-side rendering issues
const Autocomplete = dynamic(() =>
  import("../Autocomplete").then((mod) => ({ default: mod.Autocomplete })),
);

import ConditionalWrapper from "../../../utils/ConditionalWrapper";
import { Checkbox } from "../Checkbox";
import { DatePicker } from "../DatePicker";
import { FieldsetContext } from "../Fieldset/FieldsetContext";
import { File } from "../File";
import { Group } from "../Group";
import { InputStepper } from "../InputStepper";
import { Radio } from "../Radio";
import { RangeSlider } from "../RangeSlider";
import { Select } from "../Select";
import { TextArea } from "../TextArea";
import { TextInput } from "../TextInput";
import { FieldContext } from "./FieldContext";
import { getDescribedBy } from "./utils";

const CLASS_ROOT = "form-field__control";

export interface ControlProps {
  className?: string;
}

const getControlElement = (type: string) => {
  switch (type) {
    case "autocomplete":
      return Autocomplete;
    case "checkbox":
      return Checkbox;
    case "datepicker":
      return DatePicker;
    case "file":
      return File;
    case "group":
      return Group;
    case "radio":
      return Radio;
    case "range":
      return RangeSlider;
    case "select":
      return Select;
    case "input-stepper":
      return InputStepper;
    case "textarea":
      return TextArea;
    default:
      return TextInput;
  }
};

const Control: React.FC<ControlProps> = ({ className }) => {
  const context = React.useContext(FieldContext);
  const fieldsetContext = React.useContext(FieldsetContext);
  const controlId = context?.controlId ?? "";
  const control = context?.control ?? {};
  const isRadioCheck = context?.isRadioCheck;
  const hint = context?.hint;
  const messages = context?.messages ?? [];
  const tooltip = context?.tooltip;

  const fieldsetMessages = fieldsetContext?.messages ?? [];

  const {
    type,
    control: innerControl,
    renderControl,
    prefix,
    suffix,
    id: controlConfigId,
    ...controlProps
  } = control;

  const describedby = getDescribedBy(hint, messages, tooltip, controlId);
  const renderWrapper = isRadioCheck || type === "autocomplete";

  const ControlElement = getControlElement(type ?? "text");

  const { isInvalid, isValid } = controlProps;

  const hasValidationError =
    isInvalid ??
    ((fieldsetMessages.some((msg: any) => msg.isMain) ||
      messages.some((msg: any) => msg.type === "error")) &&
      !isValid);

  const props = {
    ...controlProps,
    ...(type !== "group" && { id: controlId }),
    ...(describedby.length && { "aria-describedby": describedby }),
    ...(type === "file" && { "aria-labelledby": `${controlId}-label` }),
    isInvalid: hasValidationError,
    ...(type === "group" &&
      innerControl && {
        addonPrefix: prefix,
        addonSuffix: suffix,
        control: {
          ...innerControl,
          id: controlId,
          isInvalid: hasValidationError,
        },
      }),
  };

  if (renderControl) {
    return renderControl(props);
  }

  return (
    <ConditionalWrapper
      condition={renderWrapper}
      wrapper={<div className={cx(CLASS_ROOT, className)} />}
    >
      <ControlElement
        {...props}
        className={cx(controlProps.className, {
          [`${CLASS_ROOT}`]: !renderWrapper,
        })}
      />
    </ConditionalWrapper>
  );
};

export { Control };
