"use client";

import { AlertTriangle, CheckCircle2, Info, Loader2, X, XCircle } from "lucide-react";
import type { ComponentProps, ReactNode } from "react";
import { useEffect } from "react";
import { toast, Toaster } from "sonner";
import { cn } from "@/lib/utils";
import {
  MAP_COMPACT_RADIUS_CLASS_NAME,
  MAP_ICON_CELL_RADIUS_CLASS_NAME,
  MAP_READABLE_RADIUS_CLASS_NAME
} from "./map-control-styles";

export type MapNoticeTone = "info" | "success" | "warning" | "error" | "loading";
export type MapNoticePosition = "top-center" | "top-right" | "bottom-left" | "bottom-right";

export type MapNoticeOptions = {
  id?: string | number;
  title?: string;
  message: string;
  tone?: MapNoticeTone;
  duration?: number;
  position?: MapNoticePosition;
  actionLabel?: string;
  onAction?: () => void;
  dismissible?: boolean;
};

type SonnerPosition = NonNullable<ComponentProps<typeof Toaster>["position"]>;

const DEFAULT_POSITION: MapNoticePosition = "top-center";

const positionClassNames: Record<MapNoticePosition, string> = {
  "top-center": "top-[84px]",
  "top-right": "top-[84px] right-[72px]",
  "bottom-left": "bottom-12 left-4",
  "bottom-right": "bottom-12 right-4"
};

const sonnerPositions: Record<MapNoticePosition, SonnerPosition> = {
  "top-center": "top-center",
  "top-right": "top-right",
  "bottom-left": "bottom-left",
  "bottom-right": "bottom-right"
};

const toneClassNames: Record<MapNoticeTone, string> = {
  info: "border-white/80 bg-white/95 text-slate-900",
  success: "border-white/80 bg-white/95 text-slate-900",
  warning: "border-white/80 bg-white/95 text-slate-900",
  error: "border-white/80 bg-white/95 text-slate-900",
  loading: "border-white/80 bg-white/95 text-slate-900"
};

const iconClassNames: Record<MapNoticeTone, string> = {
  info: "text-blue-600",
  success: "text-green-600",
  warning: "text-orange-500",
  error: "text-red-500",
  loading: "text-blue-600"
};

const noticeAccentClassNames: Record<MapNoticeTone, string> = {
  info: "bg-blue-600",
  success: "bg-green-500",
  warning: "bg-orange-500",
  error: "bg-red-500",
  loading: "bg-blue-600"
};

const noticeIconSurfaceClassNames: Record<MapNoticeTone, string> = {
  info: "border-blue-100 bg-blue-50",
  success: "border-green-100 bg-green-50",
  warning: "border-orange-100 bg-orange-50",
  error: "border-red-100 bg-red-50",
  loading: "border-blue-100 bg-blue-50"
};

export function MapToaster() {
  return (
    <Toaster
      closeButton={false}
      expand
      visibleToasts={4}
      position={sonnerPositions[DEFAULT_POSITION]}
      toastOptions={{
        unstyled: true,
        classNames: {
          toast: "group pointer-events-auto",
          closeButton:
            "absolute right-2 top-2 grid h-6 w-6 place-items-center rounded-lg border border-transparent text-slate-400 transition hover:bg-white/70 hover:text-slate-700"
        }
      }}
    />
  );
}

export function showMapNotice(options: MapNoticeOptions) {
  const tone = options.tone ?? "info";
  const position = options.position ?? DEFAULT_POSITION;
  const duration = options.duration ?? (tone === "info" || tone === "success" ? 3200 : Infinity);
  const dismissible = options.dismissible ?? tone !== "loading";

  return toast.custom(
    () => <MapNoticeContent {...options} tone={tone} />,
    {
      id: options.id,
      duration,
      position: sonnerPositions[position],
      dismissible,
      cancel: dismissible
        ? {
            label: <MapNoticeCloseIcon />,
            onClick: (event) => event.stopPropagation()
          }
        : undefined,
      classNames: {
        cancelButton: cn(
          "absolute right-2 top-2 z-10 grid h-7 w-7 place-items-center border border-transparent bg-transparent p-0 text-slate-400 transition hover:border-slate-200 hover:bg-slate-50 hover:text-slate-700 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-blue-600/25",
          MAP_ICON_CELL_RADIUS_CLASS_NAME
        )
      },
      className: cn("!fixed !z-[60]", positionClassNames[position])
    }
  );
}

export function dismissMapNotice(id?: string | number) {
  toast.dismiss(id);
}

export function MapErrorNotice({ message, id = "map-error" }: { message: string; id?: string | number }) {
  useEffect(() => {
    showMapNotice({
      id,
      tone: "error",
      title: "地图异常",
      message,
      duration: Infinity
    });

    return () => dismissMapNotice(id);
  }, [id, message]);

  return null;
}

export function MapLoadingNotice({
  message = "正在初始化地图...",
  title = "地图加载中",
  id = "map-loading"
}: {
  message?: string;
  title?: string;
  id?: string | number;
}) {
  useEffect(() => {
    showMapNotice({
      id,
      tone: "loading",
      title,
      message,
      duration: Infinity,
      dismissible: false
    });

    return () => dismissMapNotice(id);
  }, [id, message, title]);

  return null;
}

export type MapSourceStatus = "online" | "degraded" | "offline";

export type MapSourceStatusNoticeProps = {
  sourceName: string;
  status: MapSourceStatus;
  message?: string;
  id?: string | number;
  actionLabel?: string;
  onAction?: () => void;
};

export function MapSourceStatusNotice({
  sourceName,
  status,
  message,
  id = `map-source-${sourceName}`,
  actionLabel,
  onAction
}: MapSourceStatusNoticeProps) {
  useEffect(() => {
    showMapNotice({
      id,
      tone: getSourceStatusTone(status),
      title: getSourceStatusTitle(sourceName, status),
      message: message ?? getSourceStatusMessage(status),
      duration: status === "online" ? 2600 : Infinity,
      actionLabel,
      onAction
    });

    return () => dismissMapNotice(id);
  }, [actionLabel, id, message, onAction, sourceName, status]);

  return null;
}

function MapNoticeContent({
  title,
  message,
  tone = "info",
  actionLabel,
  onAction
}: MapNoticeOptions) {
  const Icon = getNoticeIcon(tone);

  return (
    <MapNoticeFrame tone={tone}>
      <MapNoticeIcon tone={tone} icon={Icon} />
      <MapNoticeBody
        title={title}
        message={message}
        action={actionLabel && onAction ? <MapNoticeAction label={actionLabel} onClick={onAction} /> : null}
      />
    </MapNoticeFrame>
  );
}

function MapNoticeFrame({ tone, children }: { tone: MapNoticeTone; children: ReactNode }) {
  return (
    <div
      role={tone === "error" || tone === "warning" ? "alert" : "status"}
      className={cn(
        "relative flex w-[min(420px,calc(100vw-24px))] items-start gap-2.5 overflow-hidden border py-2.5 pl-3 pr-10 text-sm shadow-lg shadow-slate-900/20 backdrop-blur-xl",
        MAP_READABLE_RADIUS_CLASS_NAME,
        toneClassNames[tone]
      )}
    >
      <span className={cn("absolute bottom-0 left-0 top-0 w-1", noticeAccentClassNames[tone])} aria-hidden="true" />
      {children}
    </div>
  );
}

function MapNoticeIcon({ tone, icon: Icon }: { tone: MapNoticeTone; icon: ReturnType<typeof getNoticeIcon> }) {
  return (
    <span
      className={cn(
        "mt-0.5 grid h-7 w-7 shrink-0 place-items-center border",
        MAP_ICON_CELL_RADIUS_CLASS_NAME,
        iconClassNames[tone],
        noticeIconSurfaceClassNames[tone]
      )}
    >
      <Icon size={17} aria-hidden="true" className={tone === "loading" ? "animate-spin" : undefined} />
    </span>
  );
}

function MapNoticeBody({
  title,
  message,
  action
}: {
  title?: string;
  message: string;
  action?: ReactNode;
}) {
  return (
    <span className="min-w-0 flex-1">
      {title ? <span className="block text-sm font-semibold leading-5 text-slate-950">{title}</span> : null}
      <span className={cn("block text-sm leading-5 text-slate-600", title && "mt-0.5")}>{message}</span>
      {action}
    </span>
  );
}

function MapNoticeAction({ label, onClick }: { label: string; onClick: () => void }) {
  return (
    <button
      type="button"
      onClick={onClick}
      className={cn("mt-2 inline-flex h-7 items-center justify-center border border-blue-100 bg-blue-50 px-2.5 text-xs font-semibold text-blue-700 transition hover:bg-blue-100", MAP_COMPACT_RADIUS_CLASS_NAME)}
    >
      {label}
    </button>
  );
}

function MapNoticeCloseIcon() {
  return (
    <>
      <span className="sr-only">关闭通知</span>
      <X size={15} aria-hidden="true" />
    </>
  );
}

function getNoticeIcon(tone: MapNoticeTone) {
  if (tone === "success") {
    return CheckCircle2;
  }

  if (tone === "warning") {
    return AlertTriangle;
  }

  if (tone === "error") {
    return XCircle;
  }

  if (tone === "loading") {
    return Loader2;
  }

  return Info;
}

function getSourceStatusTone(status: MapSourceStatus): MapNoticeTone {
  if (status === "online") {
    return "success";
  }

  if (status === "degraded") {
    return "warning";
  }

  return "error";
}

function getSourceStatusTitle(sourceName: string, status: MapSourceStatus) {
  if (status === "online") {
    return `${sourceName} 已连接`;
  }

  if (status === "degraded") {
    return `${sourceName} 降级运行`;
  }

  return `${sourceName} 不可用`;
}

function getSourceStatusMessage(status: MapSourceStatus) {
  if (status === "online") {
    return "地图数据源已恢复正常。";
  }

  if (status === "degraded") {
    return "部分地图能力不可用，系统已使用可用替代方案。";
  }

  return "地图数据源请求失败，请检查网络或稍后重试。";
}
