import { AlertTriangle, CheckCircle2, Info, Loader2, X, XCircle } from "lucide-react";
import type { ReactNode } from "react";
import { cn } from "@/shared/ui/cn";
import {
  MAP_COMPACT_RADIUS_CLASS_NAME,
  MAP_ICON_CELL_RADIUS_CLASS_NAME,
  MAP_READABLE_RADIUS_CLASS_NAME
} from "./map-control-styles";
import type { MapNoticeOptions, MapNoticeTone } from "./notice-types";

const toneClassNames: Record<MapNoticeTone, string> = {
  info: "glass-transient text-slate-900",
  success: "glass-transient text-slate-900",
  warning: "glass-transient text-slate-900",
  error: "glass-transient text-slate-900",
  loading: "glass-transient 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 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>
  );
}

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

function MapNoticeFrame({ tone, children }: { tone: MapNoticeTone; children: ReactNode }) {
  return (
    <div
      role={tone === "error" || tone === "warning" ? "alert" : "status"}
      className={cn(
        "relative flex w-full items-start gap-2.5 overflow-hidden border py-2.5 pl-3 pr-10 text-sm",
        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 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;
}
