"use client";

import * as React from "react";
import moment from "moment";
import { cva, type VariantProps } from "class-variance-authority";
import { cn } from "../../../lib/utils";

const relativeTimeCardVariants = cva(
  "inline-flex items-center gap-2 rounded-md px-2.5 py-1 text-sm font-medium",
  {
    variants: {
      variant: {
        default: "bg-muted text-muted-foreground",
        subtle: "bg-transparent text-muted-foreground",
        outline: "border border-border text-foreground",
        accent: "bg-accent text-accent-foreground",
      },
      size: {
        default: "text-sm px-2.5 py-1",
        sm: "text-xs px-2 py-0.5",
        lg: "text-base px-3 py-1.5",
      },
    },
    defaultVariants: {
      variant: "default",
      size: "default",
    },
  }
);

interface RelativeTimeCardProps
  extends React.HTMLAttributes<HTMLSpanElement>,
    VariantProps<typeof relativeTimeCardVariants> {
  /** Date value — accepts Date, string in any format, number (timestamp), or Moment */
  date: Date | string | number | moment.Moment;
  /** Input format hint if date is a string (e.g. "DD.MM.YYYY HH:mm"). Auto-detected if omitted. */
  inputFormat?: string;
  /** Display format: relative | auto | datetime | custom */
  format?: "relative" | "auto" | "datetime" | "custom";
  /** Custom output format string (moment format). Used when format="custom" */
  outputFormat?: string;
  /** Update interval in ms for relative format. @default 60000 */
  updateInterval?: number;
  /** Text before the time */
  prefix?: string;
  /** Text after the time */
  suffix?: string;
  /** Locale for display. @default "en" */
  locale?: string;
  /** Use UTC for all calculations. @default true */
  utc?: boolean;
}

function parseDate(
  value: Date | string | number | moment.Moment,
  inputFormat?: string,
  useUtc: boolean = true
): moment.Moment {
  if (moment.isMoment(value)) {
    return useUtc ? value.utc() : value.local();
  }

  const m = useUtc ? moment.utc : moment;

  if (value instanceof Date) {
    return m(value);
  }

  if (typeof value === "number") {
    return m(value);
  }

  if (typeof value === "string") {
    if (inputFormat) {
      return m(value, inputFormat, true);
    }
    return m(value);
  }

  return m();
}

function getRelativeTime(date: moment.Moment, locale: string = "en"): string {
  moment.locale(locale);
  return date.fromNow();
}

function getAutoFormat(date: moment.Moment, locale: string = "en"): string {
  moment.locale(locale);
  const now = moment();
  const diffHours = now.diff(date, "hours");
  const diffDays = now.diff(date, "days");

  if (diffHours < 24) {
    return date.format("HH:mm");
  }
  if (diffDays < 7) {
    return date.format("ddd");
  }
  if (diffDays < 365) {
    return date.format("MMM D");
  }
  return date.format("MMM D, YYYY");
}

function getDateTimeFormat(date: moment.Moment, locale: string = "en"): string {
  moment.locale(locale);
  return date.format("MMM D, YYYY HH:mm");
}

function formatDate(
  date: moment.Moment,
  format: "relative" | "auto" | "datetime" | "custom",
  locale: string,
  outputFormat?: string
): string {
  switch (format) {
    case "relative":
      return getRelativeTime(date, locale);
    case "auto":
      return getAutoFormat(date, locale);
    case "datetime":
      return getDateTimeFormat(date, locale);
    case "custom":
      moment.locale(locale);
      return date.format(outputFormat || "YYYY-MM-DD HH:mm");
  }
}

const RelativeTimeCard = React.forwardRef<
  HTMLTimeElement,
  RelativeTimeCardProps
>(
  (
    {
      date,
      inputFormat,
      format = "relative",
      outputFormat,
      updateInterval = 60000,
      prefix,
      suffix,
      locale = "en",
      utc = true,
      className,
      variant,
      size,
      ...props
    },
    ref
  ) => {
    const dateObj = React.useMemo(
      () => parseDate(date, inputFormat, utc),
      [date, inputFormat, utc]
    );

    const [display, setDisplay] = React.useState(() =>
      formatDate(dateObj, format, locale, outputFormat)
    );

    React.useEffect(() => {
      setDisplay(formatDate(dateObj, format, locale, outputFormat));
      if (format !== "relative") return;
      const id = setInterval(() => {
        setDisplay(formatDate(dateObj, format, locale, outputFormat));
      }, updateInterval);
      return () => clearInterval(id);
    }, [dateObj, format, locale, outputFormat, updateInterval]);

    const isoString = dateObj.toISOString();
    const title = dateObj.format("LLLL");

    return (
      <time
        ref={ref}
        dateTime={isoString}
        className={cn(relativeTimeCardVariants({ variant, size }), className)}
        title={title}
        {...props}
      >
        {prefix}
        {display}
        {suffix}
      </time>
    );
  }
);
RelativeTimeCard.displayName = "RelativeTimeCard";

export { RelativeTimeCard, relativeTimeCardVariants };
export type { RelativeTimeCardProps };
