'use client';

import { Bot } from 'lucide-react';
import type { CSSProperties, ReactNode } from 'react';

import { useIsPhone, useIsTabletOrBelow } from '@djangocfg/ui-core/hooks';
import { cn } from '@djangocfg/ui-core/lib';
import {
  Tooltip,
  TooltipContent,
  TooltipTrigger,
} from '@djangocfg/ui-core/components';

import { Z_INDEX } from '../constants';

export type ChatFABPosition =
  | 'bottom-right'
  | 'bottom-left'
  | 'top-right'
  | 'top-left';

export type ChatFABVariant = 'simple' | 'animated' | 'glass';
export type ChatFABSize = 'sm' | 'md' | 'lg' | 'responsive';

export interface ChatFABProps {
  /** Click handler — typically toggles a `ChatDock`. */
  onClick: () => void;
  /** Accessible label. */
  ariaLabel?: string;
  /** Icon inside the FAB. Defaults to a bot glyph. */
  icon?: ReactNode;
  /** Visual style. @default 'simple' */
  variant?: ChatFABVariant;
  /** Button size. @default 'md' */
  size?: ChatFABSize;
  /** Fixed-screen position. @default 'bottom-right' */
  position?: ChatFABPosition;
  /** Pixel offset from screen edges. @default 24 */
  offset?: number;
  /** z-index for the button. @default 99 — just below the open dock. */
  zIndex?: number;
  /** Show a small attention dot (unread / new). */
  pulse?: boolean;
  /**
   * Numeric badge — unread count. Numbers > 9 render as "9+".
   * Overrides `pulse` when both set.
   */
  badge?: number;
  /** Hover tooltip text. Shows next to the FAB on hover/focus. */
  tooltip?: string;
  /**
   * Render in-place (no fixed positioning) so the FAB sits inline in the
   * normal document flow. Useful for stories, screenshots, and previews
   * inside a contained playground panel. @default false
   */
  inline?: boolean;
  /** Override classes on the button itself. */
  className?: string;
  /** Extra style on the button (caller-controlled overrides). */
  style?: CSSProperties;
}

type ChatFABFixedSize = Exclude<ChatFABSize, 'responsive'>;

const SIZE_PX: Record<ChatFABFixedSize, number> = { sm: 44, md: 56, lg: 64 };
const ICON_PX: Record<ChatFABFixedSize, number> = { sm: 18, md: 22, lg: 26 };

/**
 * Resolve `size='responsive'` to a concrete fixed size based on the
 * viewport. Phone → `sm`, tablet → `md`, desktop → `lg`. `inline`
 * previews always collapse to `md` so stories stay stable.
 */
function useEffectiveFABSize(size: ChatFABSize, inline: boolean): ChatFABFixedSize {
  const isPhone = useIsPhone();
  const isBelowDesktop = useIsTabletOrBelow();
  if (size !== 'responsive') return size;
  if (inline) return 'md';
  if (isPhone) return 'sm';
  if (isBelowDesktop) return 'md';
  return 'lg';
}

function positionStyle(position: ChatFABPosition, offset: number): CSSProperties {
  const [vert, horiz] = position.split('-') as ['bottom' | 'top', 'right' | 'left'];
  return { [vert]: offset, [horiz]: offset } as CSSProperties;
}

function tooltipSide(position: ChatFABPosition): 'left' | 'right' {
  // Tooltip sits opposite-horizontal to the FAB so it doesn't run off-screen.
  return position.endsWith('right') ? 'left' : 'right';
}

function Badge({ value }: { value: number }) {
  const display = value > 9 ? '9+' : String(value);
  return (
    <span
      aria-hidden="true"
      className={cn(
        'absolute -right-1 -top-1 inline-flex min-w-[18px] h-[18px] items-center justify-center',
        'rounded-full bg-destructive px-1 text-[10px] font-semibold leading-none text-destructive-foreground',
        'ring-2 ring-background',
      )}
    >
      {display}
    </span>
  );
}

function PulseDot() {
  return (
    <span aria-hidden="true" className="absolute right-1 top-1">
      <span className="relative inline-flex h-2.5 w-2.5">
        <span className="absolute inset-0 rounded-full bg-destructive opacity-75 animate-ping" />
        <span className="relative inline-flex h-2.5 w-2.5 rounded-full bg-destructive ring-2 ring-background" />
      </span>
    </span>
  );
}

/**
 * Floating action button for opening a chat dock. Pure presentation — owns
 * no state. Wire it to whatever toggles your dock open.
 *
 * For the common "FAB + dock + hotkey" composition, use `<ChatLauncher>` —
 * this primitive is only useful when you need custom triggering.
 */
export function ChatFAB({
  onClick,
  ariaLabel = 'Open chat',
  icon,
  variant = 'simple',
  size = 'responsive',
  position = 'bottom-right',
  offset = 24,
  zIndex = Z_INDEX.companion,
  pulse = false,
  badge,
  tooltip,
  inline = false,
  className,
  style,
}: ChatFABProps) {
  const effectiveSize = useEffectiveFABSize(size, inline);
  const px = SIZE_PX[effectiveSize];
  const iconPx = ICON_PX[effectiveSize];
  const renderedIcon = icon ?? <Bot size={iconPx} />;

  const baseButton = cn(
    'relative grid place-items-center rounded-full focus:outline-none focus-visible:ring-2 focus-visible:ring-ring',
    'transition-transform hover:scale-105',
  );

  const fabNode =
    variant === 'animated' ? (
      <AnimatedFAB
        ariaLabel={ariaLabel}
        onClick={onClick}
        size={px}
        className={className}
        style={style}
      >
        {renderedIcon}
      </AnimatedFAB>
    ) : variant === 'glass' ? (
      <button
        type="button"
        aria-label={ariaLabel}
        onClick={onClick}
        className={cn(
          baseButton,
          'border border-border/40 bg-background/60 text-foreground shadow-lg backdrop-blur-xl',
          'hover:bg-background/80',
          className,
        )}
        style={{ width: px, height: px, ...style }}
      >
        {renderedIcon}
        {badge !== undefined ? <Badge value={badge} /> : pulse ? <PulseDot /> : null}
      </button>
    ) : (
      <button
        type="button"
        aria-label={ariaLabel}
        onClick={onClick}
        className={cn(
          baseButton,
          'bg-primary text-primary-foreground hover:bg-primary/90 shadow-2xl',
          className,
        )}
        style={{ width: px, height: px, ...style }}
      >
        {renderedIcon}
        {badge !== undefined ? <Badge value={badge} /> : pulse ? <PulseDot /> : null}
      </button>
    );

  // Wrap in our Tooltip when a tooltip label is provided. Animated variant
  // ships a wrapping <div>, so we mount the Tooltip on the FAB node directly
  // rather than relying on `asChild` forwarding through that wrapper.
  const positioned = (
    <div
      className={inline ? 'relative inline-flex' : 'fixed'}
      style={
        inline ? undefined : { ...positionStyle(position, offset), zIndex }
      }
    >
      {tooltip ? (
        <Tooltip>
          <TooltipTrigger asChild>{fabNode}</TooltipTrigger>
          <TooltipContent side={tooltipSide(position)}>{tooltip}</TooltipContent>
        </Tooltip>
      ) : (
        fabNode
      )}
    </div>
  );

  return positioned;
}

// ── Animated variant ──────────────────────────────────────────────────────
// Orbital gradient ring + glow + entrance bounce. Self-contained CSS via
// inline <style>, scoped by a unique class name per instance to avoid
// collisions when multiple FABs mount.

interface AnimatedFABProps {
  ariaLabel: string;
  onClick: () => void;
  size: number;
  className?: string;
  style?: CSSProperties;
  children: ReactNode;
}

function AnimatedFAB({ ariaLabel, onClick, size, className, style, children }: AnimatedFABProps) {
  return (
    <>
      <style>{ANIMATED_CSS}</style>
      <div
        className={cn('cmdop-fab-anim', className)}
        style={{ width: size, height: size, ...style }}
      >
        <div className="cmdop-fab-anim-glow">
          <div className="cmdop-fab-anim-wrap">
            <div className="cmdop-fab-anim-grad cmdop-fab-anim-grad-1" />
            <div className="cmdop-fab-anim-grad cmdop-fab-anim-grad-2" />
            <div className="cmdop-fab-anim-inner" />
            <button
              type="button"
              aria-label={ariaLabel}
              onClick={onClick}
              className="cmdop-fab-anim-btn"
            >
              <span className="cmdop-fab-anim-icon">{children}</span>
            </button>
          </div>
        </div>
      </div>
    </>
  );
}

const ANIMATED_CSS = `
.cmdop-fab-anim {
  position: relative;
  pointer-events: auto;
}
.cmdop-fab-anim-glow {
  width: 100%; height: 100%;
  border-radius: 50%;
  overflow: hidden;
  animation:
    cmdop-fab-entrance 0.6s cubic-bezier(0.34, 1.45, 0.64, 1) forwards,
    cmdop-fab-glow-shift 8s ease-in-out 0.6s infinite;
}
.cmdop-fab-anim-wrap {
  position: relative; width: 100%; height: 100%;
  border-radius: 50%; overflow: hidden;
}
.cmdop-fab-anim-grad { position: absolute; inset: 0; border-radius: 50%; }
.cmdop-fab-anim-grad-1 {
  background: conic-gradient(
    from 0deg,
    #fbbf24 0%, rgba(251,191,36,0) 15%,
    rgba(168,85,247,0) 20%, #a855f7 35%, rgba(168,85,247,0) 50%,
    rgba(20,184,166,0) 55%, #14b8a6 70%, rgba(20,184,166,0) 85%,
    rgba(236,72,153,0) 88%, #ec4899 97%, #fbbf24 100%
  );
  animation: cmdop-fab-rotate 7s linear infinite;
  filter: blur(1px); opacity: 0.95;
}
.cmdop-fab-anim-grad-2 {
  inset: 1px;
  background: conic-gradient(
    from 180deg,
    #a855f7 0%, rgba(168,85,247,0) 20%,
    rgba(20,184,166,0) 30%, #14b8a6 50%, rgba(20,184,166,0) 70%,
    rgba(251,191,36,0) 75%, #fbbf24 95%, #a855f7 100%
  );
  animation: cmdop-fab-rotate-rev 9s linear infinite;
  filter: blur(0.75px); opacity: 0.7;
}
.cmdop-fab-anim-inner {
  position: absolute; inset: 3px; border-radius: 50%;
  background: rgba(10, 10, 10, 0.65);
  backdrop-filter: blur(12px) saturate(1.8);
  -webkit-backdrop-filter: blur(12px) saturate(1.8);
  animation: cmdop-fab-inner-glow 5s ease-in-out infinite;
}
.cmdop-fab-anim-btn {
  position: absolute; inset: 2px;
  border-radius: 50%; border: none; background: transparent;
  cursor: pointer; display: flex; align-items: center; justify-content: center;
  transition: transform 0.2s;
}
.cmdop-fab-anim-btn:hover { transform: scale(1.06); }
.cmdop-fab-anim-icon {
  color: #fbbf24; display: flex;
  filter: drop-shadow(0 0 6px rgba(251,191,36,0.8));
  animation: cmdop-fab-icon-pulse 2.5s ease-in-out infinite;
}
@keyframes cmdop-fab-rotate { to { transform: rotate(360deg); } }
@keyframes cmdop-fab-rotate-rev { to { transform: rotate(-360deg); } }
@keyframes cmdop-fab-entrance {
  0% { transform: scale(0); }
  50% { transform: scale(1.08); }
  70% { transform: scale(0.98); }
  100% { transform: scale(1); }
}
@keyframes cmdop-fab-glow-shift {
  0%, 100% { box-shadow: 0 0 20px rgba(251,191,36,0.5), 0 0 40px rgba(168,85,247,0.3); }
  33%      { box-shadow: 0 0 20px rgba(168,85,247,0.5), 0 0 40px rgba(20,184,166,0.3); }
  66%      { box-shadow: 0 0 20px rgba(20,184,166,0.5), 0 0 40px rgba(236,72,153,0.3); }
}
@keyframes cmdop-fab-icon-pulse {
  0%, 100% { opacity: 1; transform: scale(1); }
  50%      { opacity: 0.85; transform: scale(1.15); }
}
@keyframes cmdop-fab-inner-glow {
  0%, 100% { box-shadow: inset 0 0 20px rgba(251,191,36,0.25), inset 0 0 40px rgba(168,85,247,0.15); }
  50%      { box-shadow: inset 0 0 25px rgba(168,85,247,0.3),  inset 0 0 45px rgba(20,184,166,0.2); }
}
`;
