'use client';

import { type ReactNode } from 'react';
import { File as FileIcon, X } from 'lucide-react';

import { cn } from '@djangocfg/ui-core/lib';

import { useChatDestructiveStyles } from '../styles';
import type { ChatAttachment } from '../types';

export interface AttachmentRendererArgs {
  attachment: ChatAttachment;
  /** True when shown inside the composer's staging tray (denser layout). */
  isInComposer: boolean;
  onClick?: () => void;
  onRemove?: () => void;
}

export type AttachmentRenderer = (args: AttachmentRendererArgs) => ReactNode;

export interface AttachmentRendererMap {
  image?: AttachmentRenderer;
  audio?: AttachmentRenderer;
  video?: AttachmentRenderer;
  file?: AttachmentRenderer;
  /** Fallback renderer when no per-type entry matched. */
  default?: AttachmentRenderer;
}

interface CommonProps {
  attachments: ChatAttachment[];
  maxVisible?: number;
  onClick?: (a: ChatAttachment) => void;
  onRemove?: (a: ChatAttachment) => void;
  isInComposer?: boolean;
  className?: string;
}

// ---------------------------------------------------------------------------
// AttachmentsGrid — flex-wrap, ideal for thumbnails / file chips.
// ---------------------------------------------------------------------------

export interface AttachmentsGridProps extends CommonProps {
  layout?: 'wrap' | 'grid';
}

export function AttachmentsGrid({
  attachments,
  maxVisible,
  onClick,
  onRemove,
  isInComposer = false,
  layout = 'wrap',
  className,
}: AttachmentsGridProps) {
  if (!attachments?.length) return null;
  const visible = maxVisible ? attachments.slice(0, maxVisible) : attachments;
  return (
    <div
      className={cn(
        layout === 'grid' ? 'grid grid-cols-3 gap-2' : 'flex flex-wrap gap-2',
        className,
      )}
    >
      {visible.map((a) => (
        <AttachmentTile
          key={a.id}
          attachment={a}
          isInComposer={isInComposer}
          onClick={onClick ? () => onClick(a) : undefined}
          onRemove={onRemove ? () => onRemove(a) : undefined}
        />
      ))}
    </div>
  );
}

// ---------------------------------------------------------------------------
// AttachmentsList — vertical stack, designed for rich custom renderers
// (LazyAudioPlayer, video players, document previews).
// ---------------------------------------------------------------------------

export interface AttachmentsListProps extends CommonProps {
  /** Per-type renderer overrides. Falls back to the default tile. */
  renderers?: AttachmentRendererMap;
}

export function AttachmentsList({
  attachments,
  maxVisible,
  onClick,
  onRemove,
  renderers,
  isInComposer = false,
  className,
}: AttachmentsListProps) {
  if (!attachments?.length) return null;
  const visible = maxVisible ? attachments.slice(0, maxVisible) : attachments;
  return (
    <div className={cn('flex w-full flex-col gap-2', className)}>
      {visible.map((a) => {
        const renderer = renderers?.[a.type] ?? renderers?.default;
        const args: AttachmentRendererArgs = {
          attachment: a,
          isInComposer,
          onClick: onClick ? () => onClick(a) : undefined,
          onRemove: onRemove ? () => onRemove(a) : undefined,
        };
        if (renderer) {
          return (
            <div key={a.id} className="relative w-full min-w-0">
              {renderer(args)}
              {args.onRemove ? <RemoveBtn onRemove={args.onRemove} /> : null}
            </div>
          );
        }
        return <AttachmentTile key={a.id} {...args} />;
      })}
    </div>
  );
}

// ---------------------------------------------------------------------------
// Attachments — backwards-compatible facade. Picks the right component based
// on whether `renderers` are supplied. Existing call-sites keep working.
// ---------------------------------------------------------------------------

export interface AttachmentsProps extends CommonProps {
  layout?: 'grid' | 'row';
  renderers?: AttachmentRendererMap;
}

export function Attachments(props: AttachmentsProps) {
  const { renderers, layout, ...rest } = props;
  if (renderers) {
    return <AttachmentsList {...rest} renderers={renderers} />;
  }
  return <AttachmentsGrid {...rest} layout={layout === 'grid' ? 'grid' : 'wrap'} />;
}

// ---------------------------------------------------------------------------
// Tile + remove btn (default renderers).
// ---------------------------------------------------------------------------

function AttachmentTile({ attachment, onClick, onRemove }: AttachmentRendererArgs) {
  const isImage = attachment.type === 'image';
  const isUploading = attachment.status === 'uploading';

  const inner = isImage ? (
    <img
      src={attachment.thumbnailUrl ?? attachment.url}
      alt={attachment.name ?? 'attachment'}
      className="h-16 w-16 rounded-md object-cover"
      loading="lazy"
    />
  ) : (
    <div className="flex max-w-44 items-center gap-2 rounded-md border border-border bg-background/60 px-2 py-1.5 text-xs">
      <FileIcon aria-hidden className="size-4 shrink-0 text-muted-foreground" />
      <span className="truncate">{attachment.name ?? 'file'}</span>
    </div>
  );

  return (
    <div className="relative">
      {onClick ? (
        <button type="button" onClick={onClick} className="block">
          {inner}
        </button>
      ) : (
        inner
      )}
      {isUploading ? (
        <div className="pointer-events-none absolute inset-0 flex items-center justify-center rounded-md bg-background/70 text-[10px] font-medium">
          {attachment.progress != null ? `${Math.round(attachment.progress * 100)}%` : '…'}
        </div>
      ) : null}
      {onRemove ? <RemoveBtn onRemove={onRemove} /> : null}
    </div>
  );
}

function RemoveBtn({ onRemove }: { onRemove: () => void }) {
  const styles = useChatDestructiveStyles();
  return (
    <button
      type="button"
      aria-label="Remove attachment"
      onClick={onRemove}
      className={cn(
        'absolute -right-1.5 -top-1.5 grid h-4 w-4 place-items-center rounded-full border border-border bg-background text-muted-foreground',
        styles.hoverStrong,
      )}
    >
      <X aria-hidden className="size-2.5" />
    </button>
  );
}
