"use client";

import React, { useEffect, useState, useCallback, useRef } from "react";

export type ToastType = "success" | "error" | "info" | "warning" | "default";

export interface ToastOptions {
  description?: React.ReactNode;
  duration?: number;
  action?: {
    label: string;
    onClick: () => void;
  };
}

export interface ToastItem {
  id: string;
  type: ToastType;
  title: string;
  description?: React.ReactNode;
  duration: number;
  action?: {
    label: string;
    onClick: () => void;
  };
}

type ToastListener = (toasts: ToastItem[]) => void;

class ToastStore {
  private toasts: ToastItem[] = [];
  private listeners: Set<ToastListener> = new Set();

  subscribe(listener: ToastListener): () => void {
    this.listeners.add(listener);
    listener(this.toasts);
    return () => {
      this.listeners.delete(listener);
    };
  }

  private notify() {
    this.listeners.forEach((listener) => listener([...this.toasts]));
  }

  add(type: ToastType, title: string, options?: ToastOptions): string {
    const id = `toast-${Date.now()}-${Math.random().toString(36).substring(2, 7)}`;
    const newToast: ToastItem = {
      id,
      type,
      title,
      description: options?.description,
      duration: options?.duration ?? 4000,
      action: options?.action,
    };

    // Keep up to 4 toasts at once to prevent viewport clutter
    this.toasts = [...this.toasts.slice(-3), newToast];
    this.notify();
    return id;
  }

  dismiss(id?: string) {
    if (id) {
      this.toasts = this.toasts.filter((t) => t.id !== id);
    } else {
      this.toasts = [];
    }
    this.notify();
  }
}

const toastStore = new ToastStore();

export const toast = Object.assign(
  (message: string, options?: ToastOptions) => {
    return toastStore.add("default", message, options);
  },
  {
    success: (message: string, options?: ToastOptions) =>
      toastStore.add("success", message, options),
    error: (message: string, options?: ToastOptions) =>
      toastStore.add("error", message, options),
    info: (message: string, options?: ToastOptions) =>
      toastStore.add("info", message, options),
    warning: (message: string, options?: ToastOptions) =>
      toastStore.add("warning", message, options),
    dismiss: (id?: string) => toastStore.dismiss(id),
  }
);

interface ToastCardProps {
  toastItem: ToastItem;
  onDismiss: (id: string) => void;
}

function ToastCard({ toastItem, onDismiss }: ToastCardProps) {
  const [isExiting, setIsExiting] = useState(false);
  const [isPaused, setIsPaused] = useState(false);
  const [touchOffset, setTouchOffset] = useState(0);
  const touchStartX = useRef<number | null>(null);
  const timerRef = useRef<NodeJS.Timeout | null>(null);
  const remainingTimeRef = useRef(toastItem.duration);
  const startTimeRef = useRef<number | null>(null);

  const handleDismiss = useCallback(() => {
    setIsExiting(true);
    setTimeout(() => {
      onDismiss(toastItem.id);
    }, 250);
  }, [onDismiss, toastItem.id]);

  useEffect(() => {
    if (toastItem.duration <= 0 || isPaused) return;

    startTimeRef.current = Date.now();
    timerRef.current = setTimeout(() => {
      handleDismiss();
    }, remainingTimeRef.current);

    return () => {
      if (timerRef.current) {
        clearTimeout(timerRef.current);
      }
    };
  }, [handleDismiss, isPaused, toastItem.duration]);

  const handleMouseEnter = () => {
    if (timerRef.current) {
      clearTimeout(timerRef.current);
      if (startTimeRef.current !== null) {
        const elapsed = Date.now() - startTimeRef.current;
        remainingTimeRef.current = Math.max(0, remainingTimeRef.current - elapsed);
      }
    }
    setIsPaused(true);
  };

  const handleMouseLeave = () => {
    setIsPaused(false);
  };

  // Touch Swipe to Dismiss
  const handleTouchStart = (e: React.TouchEvent) => {
    touchStartX.current = e.touches[0].clientX;
  };

  const handleTouchMove = (e: React.TouchEvent) => {
    if (touchStartX.current === null) return;
    const currentX = e.touches[0].clientX;
    const diffX = currentX - touchStartX.current;
    if (diffX > 0) {
      setTouchOffset(diffX);
    }
  };

  const handleTouchEnd = () => {
    if (touchOffset > 80) {
      handleDismiss();
    } else {
      setTouchOffset(0);
    }
    touchStartX.current = null;
  };

  // Brand token visual configs
  const styleConfig = {
    success: {
      container:
        "border-emerald-200/90 bg-emerald-50/95 text-emerald-950 shadow-[0_14px_38px_rgba(16,185,129,0.15)] ring-1 ring-emerald-400/20",
      iconBg: "bg-emerald-100/90 text-emerald-700",
      icon: "check_circle",
      badge: "Success",
    },
    error: {
      container:
        "border-rose-200/90 bg-rose-50/95 text-rose-950 shadow-[0_14px_38px_rgba(244,63,94,0.15)] ring-1 ring-rose-400/20",
      iconBg: "bg-rose-100/90 text-rose-700",
      icon: "error",
      badge: "Error",
    },
    info: {
      container:
        "border-blue-200/90 bg-blue-50/95 text-blue-950 shadow-[0_14px_38px_rgba(29,78,216,0.15)] ring-1 ring-blue-400/20",
      iconBg: "bg-blue-100/90 text-blue-700",
      icon: "info",
      badge: "Information",
    },
    warning: {
      container:
        "border-amber-200/90 bg-amber-50/95 text-amber-950 shadow-[0_14px_38px_rgba(245,158,11,0.15)] ring-1 ring-amber-400/20",
      iconBg: "bg-amber-100/90 text-amber-700",
      icon: "warning",
      badge: "Warning",
    },
    default: {
      container:
        "border-slate-200 bg-white/95 text-slate-900 shadow-[0_14px_38px_rgba(13,27,42,0.12)] ring-1 ring-slate-900/5",
      iconBg: "bg-slate-100 text-slate-700",
      icon: "notifications",
      badge: "Notification",
    },
  }[toastItem.type];

  return (
    <div
      role={toastItem.type === "error" ? "alert" : "status"}
      aria-live={toastItem.type === "error" ? "assertive" : "polite"}
      aria-atomic="true"
      onMouseEnter={handleMouseEnter}
      onMouseLeave={handleMouseLeave}
      onTouchStart={handleTouchStart}
      onTouchMove={handleTouchMove}
      onTouchEnd={handleTouchEnd}
      style={{
        transform: `translateX(${touchOffset}px)`,
        transition: touchOffset > 0 ? "none" : "all 0.25s cubic-bezier(0.16, 1, 0.3, 1)",
      }}
      className={`pointer-events-auto flex w-full max-w-md items-start gap-3 rounded-2xl border p-4 backdrop-blur-xl transition-all duration-300 ${
        styleConfig.container
      } ${
        isExiting
          ? "scale-95 opacity-0 translate-y-2"
          : "scale-100 opacity-100 translate-y-0"
      }`}
    >
      {/* Icon */}
      <span
        className={`grid h-9 w-9 shrink-0 place-items-center rounded-xl ${styleConfig.iconBg}`}
      >
        <span className="material-symbols-outlined text-[20px]">
          {styleConfig.icon}
        </span>
      </span>

      {/* Content */}
      <div className="flex-1 min-w-0 pt-0.5">
        <p className="text-sm font-extrabold leading-tight tracking-tight">
          {toastItem.title}
        </p>
        {toastItem.description && (
          <div className="mt-1 text-xs font-medium leading-relaxed opacity-85">
            {toastItem.description}
          </div>
        )}
        {toastItem.action && (
          <button
            type="button"
            onClick={() => {
              toastItem.action?.onClick();
              handleDismiss();
            }}
            className="mt-2 text-xs font-extrabold underline underline-offset-2 hover:opacity-80"
          >
            {toastItem.action.label}
          </button>
        )}
      </div>

      {/* Dismiss button */}
      <button
        type="button"
        onClick={handleDismiss}
        aria-label="Dismiss notification"
        className="shrink-0 -mr-1 -mt-1 p-1.5 rounded-lg opacity-60 hover:opacity-100 hover:bg-black/5 transition cursor-pointer"
      >
        <span className="material-symbols-outlined text-[18px] block">close</span>
      </button>
    </div>
  );
}

export function Toaster() {
  const [toasts, setToasts] = useState<ToastItem[]>([]);

  useEffect(() => {
    return toastStore.subscribe((newToasts) => {
      setToasts(newToasts);
    });
  }, []);

  if (toasts.length === 0) return null;

  return (
    <aside
      aria-label="Notifications"
      className="fixed z-[9999] pointer-events-none flex flex-col gap-2.5 bottom-4 left-4 right-4 sm:bottom-6 sm:right-6 sm:left-auto sm:w-[400px]"
    >
      {toasts.map((item) => (
        <ToastCard
          key={item.id}
          toastItem={item}
          onDismiss={(id) => toast.dismiss(id)}
        />
      ))}
    </aside>
  );
}
