import {
  Slider,
  Badge,
  Menu,
  MenuTrigger,
  MenuContent,
  MenuItem,
  IconButton,
} from '@olly/modern-sk';
import { useTranslation } from 'react-i18next';
import {
  DndContext,
  closestCenter,
  PointerSensor,
  KeyboardSensor,
  useSensor,
  useSensors,
  type DragEndEvent,
} from '@dnd-kit/core';
import {
  SortableContext,
  useSortable,
  verticalListSortingStrategy,
  sortableKeyboardCoordinates,
} from '@dnd-kit/sortable';
import { CSS } from '@dnd-kit/utilities';
import { Icon } from '../common/Icon';
import { ArtTile } from '../common/ArtTile';
import { PlayingIndicator } from '../common/PlayingIndicator';
import { useAppDispatch, useAppSelector } from '../../hooks/useAppDispatch';
import {
  goToIndex,
  removeFromQueue,
  moveInQueue,
  clearQueue,
  toggleShuffle,
  toggleLoop,
  type QueueEntry,
} from '../../store/slices/queue';
import { toggleQueue } from '../../store/slices/player';
import { openTrackInfo } from '../../store/slices/ui';
import { useResolvedQueueEntry } from '../../hooks/useResolvedQueueEntry';
import { getCoverUrl, getTrackCoverUrl } from '../../api/endpoints/streaming';

export function QueuePanel() {
  const { t } = useTranslation();
  const dispatch = useAppDispatch();
  const queue = useAppSelector((s) => s.queue);
  const isPlaying = useAppSelector((s) => s.player.isPlaying);
  const isOpen = useAppSelector((s) => s.player.isQueueOpen);

  const hasEntries = queue.entries.length > 0;
  const isRadio = queue.source === 'radio';
  const sourceLabel = queue.sourceName ?? queue.source;

  const sensors = useSensors(
    useSensor(PointerSensor, { activationConstraint: { distance: 4 } }),
    useSensor(KeyboardSensor, {
      coordinateGetter: sortableKeyboardCoordinates,
    }),
  );

  const handleDragEnd = (event: DragEndEvent) => {
    const { active, over } = event;
    if (!over || active.id === over.id) return;
    dispatch(moveInQueue({ from: Number(active.id), to: Number(over.id) }));
  };

  return (
    <aside className={`qd${isOpen ? '' : ' closed'}`} aria-hidden={!isOpen}>
      <div className="qd-inner">
        <div className="qd-head">
          <div className="row">
            <h3>{t('queue.title')}</h3>
            <div style={{ flex: 1 }} />
            <button
              type="button"
              className={`iconbtn sm${queue.shuffle ? ' on' : ''}`}
              onClick={() => dispatch(toggleShuffle())}
              title={t('queue.shuffle')}
            >
              <Icon name="shuffle" />
            </button>
            <button
              type="button"
              className={`iconbtn sm${queue.loop ? ' on' : ''}`}
              onClick={() => dispatch(toggleLoop())}
              title={t('queue.loop')}
            >
              <Icon name="repeat" />
            </button>
            <button
              type="button"
              className="iconbtn sm"
              onClick={() => dispatch(clearQueue())}
              title={t('queue.clear')}
            >
              <Icon name="trash" />
            </button>
            <button
              type="button"
              className="iconbtn sm"
              onClick={() => dispatch(toggleQueue())}
              title={t('queue.close')}
            >
              <Icon name="x" />
            </button>
          </div>
          <div className="qd-src">
            <Icon
              name={isRadio ? 'radio' : 'playlist'}
              style={{ color: isRadio ? 'var(--lime)' : 'var(--fg-3)' }}
            />
            {isRadio ? (
              <span style={{ color: 'var(--lime)' }}>
                {t('queue.radio', { source: sourceLabel })}
              </span>
            ) : (
              <span>{t('queue.from', { source: sourceLabel })}</span>
            )}
          </div>
        </div>

        <div className="qd-scroll">
          {hasEntries ? (
            <>
              {isRadio && (
                <div className="qd-radio">
                  <div className="row">
                    <Icon name="radio" />
                    <span
                      style={{
                        fontSize: 13,
                        fontWeight: 600,
                        color: 'var(--fg-1)',
                      }}
                    >
                      {t('queue.radioActive')}
                    </span>
                    <div style={{ flex: 1 }} />
                    <Badge variant="neutral">{t('queue.mixing')}</Badge>
                  </div>
                  <div className="expl">
                    <span className="lab">{t('queue.familiar')}</span>
                    <Slider
                      className="expl-slider"
                      min={0}
                      max={100}
                      step={1}
                      defaultValue={[42]}
                      aria-label="Exploration"
                    />
                    <span className="lab">{t('queue.new')}</span>
                  </div>
                </div>
              )}

              <span
                className="msk-label"
                style={{ display: 'block', margin: '4px 0 8px' }}
              >
                {t('queue.nextUp')}
              </span>
              <DndContext
                sensors={sensors}
                collisionDetection={closestCenter}
                onDragEnd={handleDragEnd}
              >
                <SortableContext
                  items={queue.entries.map((_, index) => String(index))}
                  strategy={verticalListSortingStrategy}
                >
                  {queue.entries.map((entry, index) => (
                    <QueueRow
                      key={`${entry.trackId}-${index}`}
                      id={String(index)}
                      entry={entry}
                      isCurrent={index === queue.currentIndex}
                      isPlaying={isPlaying}
                      onPlay={() => dispatch(goToIndex(index))}
                      onMoveNext={() =>
                        dispatch(
                          moveInQueue({
                            from: index,
                            to: queue.currentIndex + 1,
                          }),
                        )
                      }
                      onRemove={() => dispatch(removeFromQueue(index))}
                    />
                  ))}
                </SortableContext>
              </DndContext>

              {isRadio && (
                <div className="qd-loadmore">{t('queue.loadingMore')}</div>
              )}
            </>
          ) : (
            <div className="qd-empty">{t('queue.empty')}</div>
          )}
        </div>
      </div>
    </aside>
  );
}

/** A queue row, resolving its display fields against the live Track cache so
 * enrichment updates show. The currently-playing entry is outlined and shows
 * a playing-bars indicator in place of the drag grip. */
function QueueRow({
  id,
  entry,
  isCurrent,
  isPlaying,
  onPlay,
  onMoveNext,
  onRemove,
}: {
  id: string;
  entry: QueueEntry;
  isCurrent: boolean;
  isPlaying: boolean;
  onPlay: () => void;
  onMoveNext: () => void;
  onRemove: () => void;
}) {
  const { t } = useTranslation();
  const dispatch = useAppDispatch();
  const token = useAppSelector((s) => s.auth.accessToken);
  const resolved = useResolvedQueueEntry(entry);
  const albumTitle = resolved?.albumTitle ?? entry.albumTitle;
  const artUrl =
    getCoverUrl(resolved?.albumArtUrl) ??
    (token && resolved?.hasCover
      ? getTrackCoverUrl(resolved.trackId, token, true)
      : undefined);

  const {
    attributes,
    listeners,
    setNodeRef,
    transform,
    transition,
    isDragging,
  } = useSortable({ id });

  const style = {
    transform: CSS.Transform.toString(transform),
    transition,
    opacity: isDragging ? 0.5 : 1,
  };

  return (
    <div
      ref={setNodeRef}
      style={style}
      className={`qrow${isCurrent ? ' current' : ''}${isDragging ? ' dragging' : ''}`}
      onDoubleClick={onPlay}
      title={t('queue.doubleClickPlay')}
    >
      {isCurrent ? (
        <PlayingIndicator animate={isPlaying} />
      ) : (
        <span className="grip" {...attributes} {...listeners}>
          <Icon name="dots-six-vertical" />
        </span>
      )}
      <div className="qart">
        <ArtTile seed={albumTitle} size={36} label={albumTitle} src={artUrl} />
        {isCurrent && (
          <div className="cover-playing">
            <PlayingIndicator animate={isPlaying} />
          </div>
        )}
      </div>
      <div className="qt">
        <div className="t">{resolved?.title ?? entry.title}</div>
        <div className="r">{resolved?.artistName ?? entry.artistName}</div>
      </div>
      <Menu>
        <MenuTrigger asChild>
          <IconButton
            variant="ghost"
            size="sm"
            aria-label={t('queue.menu.options')}
          >
            ⋯
          </IconButton>
        </MenuTrigger>
        <MenuContent>
          <MenuItem onSelect={onPlay}>{t('queue.menu.playNow')}</MenuItem>
          {!isCurrent && (
            <MenuItem onSelect={onMoveNext}>
              {t('queue.menu.moveNext')}
            </MenuItem>
          )}
          <MenuItem onSelect={() => dispatch(openTrackInfo(entry.trackId))}>
            {t('queue.menu.info')}
          </MenuItem>
          <MenuItem onSelect={onRemove}>{t('queue.menu.remove')}</MenuItem>
        </MenuContent>
      </Menu>
    </div>
  );
}
