"use client"

import { toast } from "sonner"

const METHODS = ["success", "error", "info", "warning", "message", "loading"] as const
const TRAILING_PUNCTUATION_REGEX = /[\s!?.…,;:]+$/u

type ToastMethodKey = (typeof METHODS)[number]
type PatchedToast = typeof toast &
  Pick<typeof toast, ToastMethodKey | "promise"> & {
    __punctuationPatched?: boolean
  }

const patchedToast = toast as PatchedToast

function stripTrailingPunctuation(value: string): string {
  const trimmed = value.trimEnd()
  if (!trimmed) return trimmed
  return trimmed.replace(TRAILING_PUNCTUATION_REGEX, "").trimEnd()
}

function sanitizeContent<T>(value: T): T {
  if (typeof value === "string") {
    return stripTrailingPunctuation(value) as T
  }
  return value
}

function sanitizeOptions<T>(options: T): T {
  if (!options || typeof options !== "object") return options
  if ("description" in options && typeof (options as { description?: unknown }).description === "string") {
    return {
      ...(options as Record<string, unknown>),
      description: stripTrailingPunctuation((options as { description: string }).description),
    } as T
  }
  return options
}

function wrapSimpleMethod<K extends ToastMethodKey>(method: K) {
  const original = patchedToast[method]
  if (typeof original !== "function") return
  type ToastFn = (...args: unknown[]) => unknown
  const callable = original as ToastFn
  const patched = ((...args: Parameters<ToastFn>) => {
    const nextArgs = args.slice()
    if (nextArgs.length > 0) {
      nextArgs[0] = sanitizeContent(nextArgs[0])
    }
    if (nextArgs.length > 1) {
      nextArgs[1] = sanitizeOptions(nextArgs[1])
    }
    return callable(...nextArgs)
  }) as typeof patchedToast[K]
  patchedToast[method] = patched
}

function wrapPromise() {
  const originalPromise = patchedToast.promise
  if (typeof originalPromise !== "function") return
  patchedToast.promise = ((promise, messages) => {
    const normalizedMessages =
      messages && typeof messages === "object"
        ? ({
            ...messages,
            loading: sanitizeContent(messages.loading),
            success: sanitizeContent(messages.success),
            error: sanitizeContent(messages.error),
            description: sanitizeContent(messages.description),
          } satisfies typeof messages)
        : messages

    return originalPromise(promise, normalizedMessages)
  }) as typeof toast.promise
}

if (!patchedToast.__punctuationPatched) {
  patchedToast.__punctuationPatched = true
  METHODS.forEach(wrapSimpleMethod)
  wrapPromise()
}
