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

export type TimelineOrientation = "vertical" | "horizontal";
export type TimelineVariant = "default" | "icon";
export type TimelineItemState = "finished" | "active" | "inactive";

export type TimelineStep = {
  bottomDate?: string;
  caption?: string;
  date?: string;
  icon?: ReactNode;
  id?: string;
  label?: string;
  showBottomDate?: boolean;
  showCaption?: boolean;
  showLeadingDate?: boolean;
  showLine?: boolean;
  showPaddingBottom?: boolean;
  showTopDate?: boolean;
  state?: TimelineItemState;
  topDate?: string;
};

export type TimelineItemProps = TimelineStep & {
  className?: string;
  dir?: "ltr" | "rtl";
  orientation?: TimelineOrientation;
  variant?: TimelineVariant;
};

export type TimelineProps = {
  ariaLabel?: string;
  className?: string;
  dir?: "ltr" | "rtl";
  orientation?: TimelineOrientation;
  steps?: TimelineStep[];
  variant?: TimelineVariant;
};

function classes(...names: Array<string | false | undefined>) {
  return names.filter(Boolean).join(" ");
}

function Indicator({
  icon,
  orientation,
  rtl,
  showLine,
  state,
  variant,
}: {
  icon?: ReactNode;
  orientation: TimelineOrientation;
  rtl: boolean;
  showLine: boolean;
  state: TimelineItemState;
  variant: TimelineVariant;
}) {
  const marker = (
    <span
      aria-hidden="true"
      className={classes(
        "ds-timeline__marker",
        `ds-timeline__marker--${variant}`,
        `ds-timeline__marker--${state}`,
      )}
    >
      {variant === "icon" && (icon ?? <CheckIcon />)}
    </span>
  );
  const line = showLine ? (
    <span aria-hidden="true" className={classes("ds-timeline__line", `ds-timeline__line--${state}`)} />
  ) : null;

  return (
    <span
      className={classes(
        "ds-timeline__indicator",
        `ds-timeline__indicator--${orientation}`,
        rtl && "ds-timeline__indicator--rtl",
      )}
      aria-hidden="true"
    >
      {orientation === "horizontal" && rtl ? (
        <>
          {line}
          {marker}
        </>
      ) : (
        <>
          {marker}
          {line}
        </>
      )}
    </span>
  );
}

export function TimelineItem({
  bottomDate,
  caption,
  className,
  date,
  dir = "ltr",
  icon,
  label,
  orientation = "vertical",
  showBottomDate = false,
  showCaption = true,
  showLeadingDate = true,
  showLine = true,
  showPaddingBottom,
  showTopDate = false,
  state = "finished",
  topDate,
  variant = "default",
}: TimelineItemProps) {
  const rtl = dir === "rtl";
  const displayDate = date;
  const displayLabel = label;
  const displayCaption = caption;
  const displayTopDate = topDate ?? displayDate;
  const displayBottomDate = bottomDate ?? displayDate;
  const hasPaddingBottom = showPaddingBottom ?? orientation === "vertical";

  const body = (
    <span className="ds-timeline__body">
      {showTopDate && displayTopDate && <span className="ds-timeline__date ds-timeline__date--top">{displayTopDate}</span>}
      <span className="ds-timeline__copy">
        {displayLabel && <span className="ds-timeline__label">{displayLabel}</span>}
        {showCaption && displayCaption && <span className="ds-timeline__caption">{displayCaption}</span>}
      </span>
      {showBottomDate && displayBottomDate && <span className="ds-timeline__date ds-timeline__date--bottom">{displayBottomDate}</span>}
      {hasPaddingBottom && <span aria-hidden="true" className="ds-timeline__bottom-space" />}
    </span>
  );

  const indicator = (
    <Indicator
      icon={icon}
      orientation={orientation}
      rtl={rtl}
      showLine={showLine}
      state={state}
      variant={variant}
    />
  );

  const leadingDate = showLeadingDate && displayDate ? (
    <span className="ds-timeline__date ds-timeline__date--leading">{displayDate}</span>
  ) : null;

  return (
    <div
      className={classes(
        "ds-timeline-item",
        `ds-timeline-item--${orientation}`,
        `ds-timeline-item--${variant}`,
        `ds-timeline-item--${state}`,
        rtl ? "ds-timeline-item--rtl" : "ds-timeline-item--ltr",
        className,
      )}
      dir={dir}
      role="listitem"
    >
      {orientation === "vertical" && rtl ? (
        <>
          {body}
          {indicator}
          {leadingDate}
        </>
      ) : orientation === "vertical" ? (
        <>
          {leadingDate}
          {indicator}
          {body}
        </>
      ) : (
        <>
          {leadingDate}
          {indicator}
          {body}
        </>
      )}
    </div>
  );
}

export function Timeline({
  ariaLabel,
  className,
  dir = "ltr",
  orientation = "vertical",
  steps = [],
  variant = "default",
}: TimelineProps) {
  const rtl = dir === "rtl";

  return (
    <div
      aria-label={ariaLabel}
      className={classes(
        "ds-timeline",
        `ds-timeline--${orientation}`,
        `ds-timeline--${variant}`,
        rtl ? "ds-timeline--rtl" : "ds-timeline--ltr",
        className,
      )}
      dir={dir}
      role="list"
    >
      {steps.map((step, index) => (
        <TimelineItem
          {...step}
          key={step.id ?? index}
          dir={dir}
          orientation={orientation}
          showTopDate={step.showTopDate ?? orientation === "horizontal"}
          showBottomDate={step.showBottomDate ?? false}
          showPaddingBottom={step.showPaddingBottom ?? orientation === "vertical"}
          variant={variant}
        />
      ))}
    </div>
  );
}

function CheckIcon() {
  return (
    <svg aria-hidden="true" className="ds-timeline__check" fill="none" viewBox="0 0 18 18">
      <path d="m6.98 11.5 5.1-5.1 1.06 1.06-6.16 6.16-3.3-3.3 1.06-1.06 2.24 2.24Z" fill="currentColor" />
    </svg>
  );
}
