import {
  differenceInCalendarDays,
  differenceInDays,
  differenceInHours,
  differenceInMinutes,
  differenceInMonths,
  differenceInSeconds,
  differenceInYears,
  format,
  isValid,
} from "date-fns";
import { formatInTimeZone } from "date-fns-tz";

export enum ValidUnit {
  DAYS = "days",
  MONTHS = "months",
  YEARS = "years",
}

export const formatDate = (date?: Date | string | null): string => {
  if (!date) return "-";

  const parsedDate = new Date(date);
  if (!isValid(parsedDate)) return "-";

  return format(parsedDate, "dd MMM yyyy");
};
export const formatDateTime = (date: Date) => {
  return format(date, "dd MMM yyyy, h:mm a");
};

export function formatActivityDate(date: string): string {
  if (!date) return "N/A";
  return new Intl.DateTimeFormat("en-US", {
    year: "numeric",
    month: "short",
    day: "numeric",
    hour: "2-digit",
    minute: "2-digit",
  }).format(new Date(date));
}

export const supportDate = (isoDate: string) => {
  const date = new Date(isoDate);
  const now = new Date();

  const isToday =
    date.getDate() === now.getDate() &&
    date.getMonth() === now.getMonth() &&
    date.getFullYear() === now.getFullYear();

  return isToday
    ? "Today"
    : date.toLocaleDateString(undefined, {
        month: "short",
        day: "numeric",
        year: "numeric",
      });
};

export const supportTime = (isoDate: string) => {
  const date = new Date(isoDate);
  const now = new Date();

  const isToday =
    date.getDate() === now.getDate() &&
    date.getMonth() === now.getMonth() &&
    date.getFullYear() === now.getFullYear();

  if (isToday) {
    const diffMs = now.getTime() - date.getTime();
    const diffHours = Math.floor(diffMs / (1000 * 60 * 60));
    const diffMinutes = Math.floor(diffMs / (1000 * 60));

    if (diffHours >= 1)
      return `${diffHours} hour${diffHours > 1 ? "s" : ""} ago`;
    else return `${diffMinutes} minute${diffMinutes > 1 ? "s" : ""} ago`;
  }

  return date.toLocaleTimeString(undefined, {
    hour: "numeric",
    minute: "numeric",
    hour12: true,
  });
};

export function getGreetingFromHour(hour: number) {
  if (hour < 12) return "Good morning";
  if (hour < 17) return "Good afternoon";
  return "Good evening";
}

export const getDaysAgo = (date: Date): string => {
  const days = differenceInCalendarDays(new Date(), date);

  if (days === 0) return "Today";
  if (days === 1) return "1 day ago";
  return `${days} days ago`;
};

/**
 * Format an ISO date string as relative time (e.g. "2 minutes ago", "3 hours ago").
 */
export const formatTimeAgo = (date: string | Date | undefined | null): string => {
  if (!date) return "-";
  const parsed = typeof date === "string" ? new Date(date) : date;
  if (!isValid(parsed)) return "-";
  const now = new Date();
  const secs = differenceInSeconds(now, parsed);
  const mins = differenceInMinutes(now, parsed);
  const hours = differenceInHours(now, parsed);
  const days = differenceInCalendarDays(now, parsed);
  const months = differenceInMonths(now, parsed);
  const years = differenceInYears(now, parsed);

  if (secs < 60) return secs <= 5 ? "just now" : `${secs} seconds ago`;
  if (mins < 60) return mins === 1 ? "1 minute ago" : `${mins} minutes ago`;
  if (hours < 24) return hours === 1 ? "1 hour ago" : `${hours} hours ago`;
  if (days < 30) return days === 1 ? "1 day ago" : `${days} days ago`;
  if (months < 12) return months === 1 ? "1 month ago" : `${months} months ago`;
  return years === 1 ? "1 year ago" : `${years} years ago`;
};

export const formatDateWithTime = (date: string | Date | undefined | null) => {
  if (!date) return "-";

  const parsedDate = typeof date === "string" ? new Date(date) : date;
  if (isNaN(parsedDate.getTime())) return "-";

  return formatInTimeZone(parsedDate, "UTC", "dd MMM yyyy, h:mm a"); // Forces UTC time
};

export const getCurrentMonthYear = () => {
  const today = new Date();
  return {
    month: today.getMonth() + 1,
    year: today.getFullYear(),
  };
};

export const formatDateWithIST = (
  date: string | Date | undefined | null,
  formatStr: string = "dd MMM yyyy, h:mm a"
) => {
  if (!date) return "-";

  const parsedDate = typeof date === "string" ? new Date(date) : date;

  // Check for invalid dates
  if (isNaN(parsedDate.getTime())) return "-";

  return formatInTimeZone(parsedDate, "Asia/Kolkata", formatStr);
};

export const formatRelativeDayWithTime = (
  date: string | Date | undefined | null,
  formatStr: string = "dd MMM yyyy, h:mm a"
): string => {
  if (!date) return "-";

  const parsedDate = typeof date === "string" ? new Date(date) : date;
  if (isNaN(parsedDate.getTime())) return "-";

  const diffDays = differenceInCalendarDays(parsedDate, new Date());
  if (diffDays === 0) return `Today, ${format(parsedDate, "h:mm a")}`;
  if (diffDays === -1) return `Yesterday, ${format(parsedDate, "h:mm a")}`;
  if (diffDays === 1) return `Tomorrow, ${format(parsedDate, "h:mm a")}`;

  return format(parsedDate, formatStr);
};

export function calculateExpiryDate(
  issuedDate: string | Date,
  validfor: number,
  validUnit: ValidUnit
): Date {
  const date = new Date(issuedDate);

  switch (validUnit) {
    case ValidUnit.DAYS:
      date.setDate(date.getDate() + validfor);
      break;
    case ValidUnit.MONTHS:
      date.setMonth(date.getMonth() + validfor);
      break;
    case ValidUnit.YEARS:
      date.setFullYear(date.getFullYear() + validfor);
      break;
    default:
      throw new Error(`Unsupported validity unit: ${validUnit}`);
  }

  return date;
}
