import type { ReactNode } from "react";
import "./steps.css";

export type StepIndicator = "icon" | "number";
export type StepDirection = "horizontal" | "vertical";
export type StepAlignment = "leading" | "middle" | "trailing";
export type StepPosition = "top" | "bottom";

export type StepItem = {
  actions?: ReactNode;
  caption?: ReactNode;
  label?: ReactNode;
  number?: ReactNode;
  slotContent?: ReactNode;
  supportText?: ReactNode;
};

export type StepsProps = {
  alignment?: Exclude<StepAlignment, "middle">;
  className?: string;
  dir?: "ltr" | "rtl";
  direction?: StepDirection;
  indicator?: StepIndicator;
  items?: StepItem[];
};

export type HorizontalStepItemProps = {
  alignment?: StepAlignment;
  caption?: ReactNode;
  className?: string;
  hasCaption?: boolean;
  indicator?: StepIndicator;
  label?: ReactNode;
  number?: ReactNode;
  position?: StepPosition;
  dir?: "ltr" | "rtl";
  showLeadingLine?: boolean;
  showTrailingLine?: boolean;
};

export type VerticalStepItemProps = {
  actions?: ReactNode;
  alignment?: Exclude<StepAlignment, "middle">;
  caption?: ReactNode;
  className?: string;
  hasActionButtons?: boolean;
  hasCaption?: boolean;
  hasSlotContent?: boolean;
  hasSupportText?: boolean;
  indicator?: StepIndicator;
  label?: ReactNode;
  number?: ReactNode;
  dir?: "ltr" | "rtl";
  showBottomPadding?: boolean;
  showLine?: boolean;
  slotContent?: ReactNode;
  supportText?: ReactNode;
};

export function Steps({
  alignment = "leading",
  className = "",
  dir = "ltr",
  direction = "horizontal",
  indicator = "icon",
  items,
}: StepsProps) {
  const rtl = dir === "rtl";
  const stepItems = items ?? [];

  if (direction === "vertical") {
    return (
      <div
        className={["ds-steps", "ds-steps--vertical", rtl ? "ds-steps--rtl" : "ds-steps--ltr", className]
          .filter(Boolean)
          .join(" ")}
        dir={dir}
      >
        {stepItems.map((item, index) => (
          <VerticalStepItem
            alignment={alignment}
            caption={item.caption}
            hasActionButtons={Boolean(item.actions)}
            hasSlotContent={Boolean(item.slotContent)}
            indicator={indicator}
            key={index}
            label={item.label}
            number={item.number ?? index + 1}
            dir={dir}
            showBottomPadding={index < stepItems.length - 1}
            showLine={index < stepItems.length - 1}
            slotContent={item.slotContent}
            supportText={item.supportText}
          >
            {item.actions}
          </VerticalStepItem>
        ))}
      </div>
    );
  }

  return (
    <div
      className={["ds-steps", "ds-steps--horizontal", rtl ? "ds-steps--rtl" : "ds-steps--ltr", className]
        .filter(Boolean)
        .join(" ")}
      dir={dir}
    >
      {stepItems.map((item, index) => (
        <HorizontalStepItem
          caption={item.caption}
          hasCaption={item.caption !== null && item.caption !== undefined}
          indicator={indicator}
          key={index}
          label={item.label}
          number={item.number ?? index + 1}
          dir={dir}
        />
      ))}
    </div>
  );
}

export function HorizontalStepItem({
  alignment = "leading",
  caption,
  className = "",
  hasCaption = true,
  indicator = "icon",
  label,
  number = 1,
  position = "top",
  dir = "ltr",
  showLeadingLine = true,
  showTrailingLine = true,
}: HorizontalStepItemProps) {
  const rtl = dir === "rtl";
  const linePlacement = getHorizontalLinePlacement(alignment, rtl, showLeadingLine, showTrailingLine);
  const text = (
    <div className="ds-horizontal-step-item__text">
      {label && <div className="ds-horizontal-step-item__label">{label}</div>}
      {hasCaption && caption && <div className="ds-horizontal-step-item__caption">{caption}</div>}
    </div>
  );
  const track = (
    <div className="ds-horizontal-step-item__track" aria-hidden="true">
      {linePlacement.before && <span className="ds-step-line ds-step-line--horizontal" />}
      <StepMarker indicator={indicator} number={number} />
      {linePlacement.after && <span className="ds-step-line ds-step-line--horizontal" />}
    </div>
  );

  return (
    <div
      className={[
        "ds-horizontal-step-item",
        `ds-horizontal-step-item--${alignment}`,
        `ds-horizontal-step-item--${position}`,
        rtl ? "ds-horizontal-step-item--rtl" : "ds-horizontal-step-item--ltr",
        className,
      ]
        .filter(Boolean)
        .join(" ")}
      dir={dir}
    >
      {position === "bottom" ? text : track}
      {position === "bottom" ? track : text}
    </div>
  );
}

export function VerticalStepItem({
  actions,
  alignment = "leading",
  caption,
  children,
  className = "",
  hasActionButtons = true,
  hasCaption = true,
  hasSlotContent = true,
  hasSupportText = true,
  indicator = "icon",
  label,
  number = 1,
  dir = "ltr",
  showBottomPadding = true,
  showLine = true,
  slotContent,
  supportText,
}: VerticalStepItemProps & { children?: ReactNode }) {
  const rtl = dir === "rtl";
  const marker = (
    <div className="ds-vertical-step-item__rail" aria-hidden="true">
      <StepMarker indicator={indicator} number={number} />
      {showLine && <span className="ds-step-line ds-step-line--vertical" />}
    </div>
  );
  const markerFirst = (alignment === "leading" && !rtl) || (alignment === "trailing" && rtl);
  const renderedActions = actions ?? children;
  const renderedSlot = slotContent;

  return (
    <div
      className={[
        "ds-vertical-step-item",
        `ds-vertical-step-item--${alignment}`,
        rtl ? "ds-vertical-step-item--rtl" : "ds-vertical-step-item--ltr",
        className,
      ]
        .filter(Boolean)
        .join(" ")}
      dir={dir}
    >
      {markerFirst && marker}
      <div className="ds-vertical-step-item__content">
        <div className="ds-vertical-step-item__copy">
          <div className="ds-vertical-step-item__header">
            {rtl && hasSupportText && supportText && <div className="ds-vertical-step-item__support">{supportText}</div>}
            {label && <div className="ds-vertical-step-item__label">{label}</div>}
            {!rtl && hasSupportText && supportText && <div className="ds-vertical-step-item__support">{supportText}</div>}
          </div>
          {hasCaption && caption && <div className="ds-vertical-step-item__caption">{caption}</div>}
        </div>
        {hasSlotContent && renderedSlot}
        {hasActionButtons && renderedActions && <div className="ds-vertical-step-item__actions">{renderedActions}</div>}
        {showBottomPadding && <div className="ds-vertical-step-item__bottom-padding" />}
      </div>
      {!markerFirst && marker}
    </div>
  );
}

function StepMarker({ indicator, number }: { indicator: StepIndicator; number: ReactNode }) {
  if (indicator === "number") {
    return (
      <span className="ds-step-marker ds-step-marker--number">
        <span>{number}</span>
      </span>
    );
  }

  return (
    <span className="ds-step-marker ds-step-marker--icon">
      <svg aria-hidden="true" focusable="false" viewBox="0 0 24 24">
        <path d="m10.6 15.3-3.3-3.3 1.4-1.4 1.9 1.9 4.7-4.7 1.4 1.4-6.1 6.1Z" />
      </svg>
    </span>
  );
}

function getHorizontalLinePlacement(
  alignment: StepAlignment,
  rtl: boolean,
  showLeadingLine: boolean,
  showTrailingLine: boolean,
) {
  if (alignment === "middle") {
    return { before: showLeadingLine, after: showTrailingLine };
  }

  if (alignment === "leading") {
    return rtl ? { before: showTrailingLine, after: false } : { before: false, after: showTrailingLine };
  }

  return rtl ? { before: false, after: showLeadingLine } : { before: showLeadingLine, after: false };
}
