import { queueSongStar } from '@/features/playback/store/pendingStarSync';
import { getSong } from '@/lib/api/subsonicLibrary';
import { songToTrack } from '@/lib/media/songToTrack';
import { openMiniPlayer } from '@/lib/api/miniPlayer';
import { audioStop } from '@/lib/api/audio';
import { getCurrentWindow } from '@tauri-apps/api/window';
import i18n from '@/lib/i18n';
import { usePlayerStore } from '@/features/playback/store/playerStore';
import { usePreviewStore } from '@/features/playback/store/previewStore';
import { useLyricsStore } from '../store/lyricsStore';
import { showToast } from '@/lib/dom/toast';
import type { ActionContext, ShortcutSlot, ShortcutActionMeta } from '@/config/shortcutTypes';

let cliPremuteVolume: number | null = null;

const withPreviewPolicy = (
  action: 'play' | 'pause' | 'stop' | 'play-pause' | 'next' | 'prev',
  options: ActionContext,
  fn: () => void
) => {
  const previewing = usePreviewStore.getState().previewingId !== null;
  if (previewing && options.previewPolicy === 'ignore') return;
  if (previewing && options.previewPolicy === 'stop') {
    usePreviewStore.getState().stopPreview();
  }
  fn();
};

function focusLiveSearchInput(): boolean {
  const input = document.getElementById('live-search-input') as HTMLInputElement | null;
  if (!input) return false;
  input.focus();
  input.select();
  return true;
}


export const SHORTCUT_ACTION_REGISTRY = {
  'play': {
    getLabel: t => t('settings.shortcutPlayPause'),
    runInMiniWindow: false,
    run: ({ previewPolicy }) => withPreviewPolicy('play', { navigate: () => {}, previewPolicy }, () => {
      const state = usePlayerStore.getState();
      if (!state.isPlaying) state.resume();
    }),
    cli: { verb: 'play', description: 'play' },
  },
  'pause': {
    getLabel: t => t('settings.shortcutPlayPause'),
    runInMiniWindow: false,
    run: ({ previewPolicy }) => withPreviewPolicy('pause', { navigate: () => {}, previewPolicy }, () => {
      const state = usePlayerStore.getState();
      if (state.isPlaying) state.pause();
    }),
    cli: { verb: 'pause', description: 'pause' },
  },
  'stop': {
    getLabel: t => t('settings.shortcutPlayPause'),
    runInMiniWindow: false,
    run: ({ previewPolicy }) => withPreviewPolicy('stop', { navigate: () => {}, previewPolicy }, () => {
      usePlayerStore.getState().stop();
    }),
    cli: { verb: 'stop', description: 'stop' },
  },
  'play-pause': {
    getLabel: t => t('settings.shortcutPlayPause'),
    inApp: { defaultBinding: 'Space' },
    global: { defaultBinding: null },
    runInMiniWindow: true,
    run: ({ previewPolicy }) => withPreviewPolicy('play-pause', { navigate: () => {}, previewPolicy }, () => {
      usePlayerStore.getState().togglePlay();
    }),
  },
  next: {
    getLabel: t => t('settings.shortcutNext'),
    inApp: { defaultBinding: null },
    global: { defaultBinding: null },
    runInMiniWindow: true,
    run: ({ previewPolicy }) => withPreviewPolicy('next', { navigate: () => {}, previewPolicy }, () => {
      usePlayerStore.getState().next();
    }),
    cli: { verb: 'next', description: 'next track' },
  },
  prev: {
    getLabel: t => t('settings.shortcutPrev'),
    inApp: { defaultBinding: null },
    global: { defaultBinding: null },
    runInMiniWindow: true,
    run: ({ previewPolicy }) => withPreviewPolicy('prev', { navigate: () => {}, previewPolicy }, () => {
      usePlayerStore.getState().previous();
    }),
    cli: { verb: 'prev', description: 'previous track' },
  },
  'volume-up': {
    getLabel: t => t('settings.shortcutVolumeUp'),
    inApp: { defaultBinding: null },
    global: { defaultBinding: null },
    runInMiniWindow: false,
    run: () => {
      const state = usePlayerStore.getState();
      state.setVolume(Math.min(1, state.volume + 0.05));
    },
  },
  'volume-down': {
    getLabel: t => t('settings.shortcutVolumeDown'),
    inApp: { defaultBinding: null },
    global: { defaultBinding: null },
    runInMiniWindow: false,
    run: () => {
      const state = usePlayerStore.getState();
      state.setVolume(Math.max(0, state.volume - 0.05));
    },
  },
  'seek-forward': {
    getLabel: t => t('settings.shortcutSeekForward'),
    inApp: { defaultBinding: null },
    runInMiniWindow: false,
    run: () => {
      const state = usePlayerStore.getState();
      const duration = state.currentTrack?.duration ?? 0;
      if (!duration) return;
      state.seek(Math.min(1, (state.currentTime + 10) / duration));
    },
  },
  'seek-backward': {
    getLabel: t => t('settings.shortcutSeekBackward'),
    inApp: { defaultBinding: null },
    runInMiniWindow: false,
    run: () => {
      const state = usePlayerStore.getState();
      const duration = state.currentTrack?.duration ?? 0;
      if (!duration) return;
      state.seek(Math.max(0, (state.currentTime - 10) / duration));
    },
  },
  'toggle-queue': {
    getLabel: t => t('settings.shortcutToggleQueue'),
    inApp: { defaultBinding: null },
    runInMiniWindow: false,
    run: () => {
      usePlayerStore.getState().toggleQueue();
    },
  },
  'open-folder-browser': {
    getLabel: t => t('settings.shortcutOpenFolderBrowser', { folderBrowser: t('sidebar.folderBrowser') }),
    inApp: { defaultBinding: null },
    runInMiniWindow: false,
    run: ({ navigate }) => {
      navigate('/folders', { state: { folderBrowserRevealTs: Date.now() } });
    },
  },
  'fullscreen-player': {
    getLabel: t => t('settings.shortcutFullscreenPlayer'),
    inApp: { defaultBinding: null },
    runInMiniWindow: false,
    run: () => {
      usePlayerStore.getState().toggleFullscreen();
    },
  },
  'native-fullscreen': {
    getLabel: t => t('settings.shortcutNativeFullscreen'),
    inApp: { defaultBinding: 'F11' },
    runInMiniWindow: false,
    run: () => {
      const win = getCurrentWindow();
      win.isFullscreen().then(fs => win.setFullscreen(!fs));
    },
  },
  'open-mini-player': {
    getLabel: t => t('settings.shortcutOpenMiniPlayer'),
    inApp: { defaultBinding: null },
    runInMiniWindow: true,
    run: () => {
      openMiniPlayer().catch(() => {});
    },
  },
  'start-search': {
    getLabel: t => t('settings.shortcutStartSearch', { defaultValue: 'Start a search' }),
    inApp: { defaultBinding: null },
    runInMiniWindow: false,
    run: ({ navigate }) => {
      if (focusLiveSearchInput()) return;
      navigate('/');
      requestAnimationFrame(() => {
        window.setTimeout(() => { focusLiveSearchInput(); }, 80);
      });
    },
  },
  'start-advanced-search': {
    getLabel: t => t('settings.shortcutStartAdvancedSearch', { defaultValue: 'Start an advanced search' }),
    inApp: { defaultBinding: null },
    runInMiniWindow: false,
    run: ({ navigate }) => {
      navigate('/search/advanced');
    },
  },
  'toggle-sidebar': {
    getLabel: t => t('settings.shortcutToggleSidebar', { defaultValue: 'Toggle sidebar' }),
    inApp: { defaultBinding: null },
    runInMiniWindow: false,
    run: () => {
      window.dispatchEvent(new Event('psy:toggle-sidebar'));
    },
  },
  'mute-sound': {
    getLabel: t => t('settings.shortcutMuteSound', { defaultValue: 'Mute sound' }),
    inApp: { defaultBinding: null },
    runInMiniWindow: false,
    run: () => {
      const state = usePlayerStore.getState();
      if (state.volume <= 0) {
        const restore = cliPremuteVolume ?? 0.8;
        cliPremuteVolume = null;
        state.setVolume(restore);
        return;
      }
      cliPremuteVolume = state.volume;
      state.setVolume(0);
    },
  },
  'toggle-equalizer': {
    getLabel: t => t('settings.shortcutToggleEqualizer', { defaultValue: 'Open / Toggle Equalizer' }),
    inApp: { defaultBinding: null },
    runInMiniWindow: false,
    run: () => {
      window.dispatchEvent(new Event('psy:toggle-equalizer'));
    },
  },
  'toggle-repeat': {
    getLabel: t => t('settings.shortcutToggleRepeat', { defaultValue: 'Toggle repeat' }),
    inApp: { defaultBinding: null },
    runInMiniWindow: false,
    run: () => {
      usePlayerStore.getState().toggleRepeat();
    },
  },
  'open-now-playing': {
    getLabel: t => t('settings.shortcutOpenNowPlaying', { defaultValue: 'Open "Now Playing"' }),
    inApp: { defaultBinding: null },
    runInMiniWindow: false,
    run: ({ navigate }) => {
      navigate('/now-playing');
    },
  },
  'show-lyrics': {
    getLabel: t => t('settings.shortcutShowLyrics', { defaultValue: 'Show lyrics' }),
    inApp: { defaultBinding: null },
    runInMiniWindow: false,
    run: () => {
      const player = usePlayerStore.getState();
      player.setQueueVisible(true);
      useLyricsStore.getState().showLyrics();
    },
  },
  'favorite-current-track': {
    getLabel: t => t('settings.shortcutFavoriteCurrentTrack', { defaultValue: 'Add current track to favorites' }),
    inApp: { defaultBinding: null },
    runInMiniWindow: false,
    run: () => {
      const track = usePlayerStore.getState().currentTrack;
      if (!track) {
        showToast(i18n.t('contextMenu.cliMixNeedsTrack', { defaultValue: 'Load a track first.' }), 5000, 'error');
        return;
      }
      queueSongStar(track.id, true, track.serverId);
    },
  },
  'open-help': {
    getLabel: t => t('settings.shortcutOpenHelp', { defaultValue: 'Help' }),
    inApp: { defaultBinding: 'F1', hidden: true },
    runInMiniWindow: false,
    run: ({ navigate }) => {
      navigate('/help');
    },
  },
  'shuffle': {
    getLabel: t => t('settings.shortcutNext'),
    runInMiniWindow: false,
    run: () => {
      usePlayerStore.getState().shuffleQueue();
    },
    cli: { verb: 'shuffle', description: 'shuffle' },
  },
  'mute': {
    getLabel: t => t('settings.shortcutVolumeDown'),
    runInMiniWindow: false,
    run: () => {
      const state = usePlayerStore.getState();
      if (state.volume > 0) cliPremuteVolume = state.volume;
      state.setVolume(0);
    },
    cli: { verb: 'mute', description: 'mute' },
  },
  'unmute': {
    getLabel: t => t('settings.shortcutVolumeUp'),
    runInMiniWindow: false,
    run: () => {
      const restore = cliPremuteVolume ?? 0.8;
      cliPremuteVolume = null;
      usePlayerStore.getState().setVolume(restore);
    },
    cli: { verb: 'unmute', description: 'unmute' },
  },
  'star': {
    getLabel: t => t('settings.shortcutPlayPause'),
    runInMiniWindow: false,
    run: () => {
      const track = usePlayerStore.getState().currentTrack;
      if (!track) {
        showToast(i18n.t('contextMenu.cliMixNeedsTrack'), 5000, 'error');
        return;
      }
      queueSongStar(track.id, true, track.serverId);
    },
    cli: { verb: 'star', description: 'star' },
  },
  'unstar': {
    getLabel: t => t('settings.shortcutPlayPause'),
    runInMiniWindow: false,
    run: () => {
      const track = usePlayerStore.getState().currentTrack;
      if (!track) {
        showToast(i18n.t('contextMenu.cliMixNeedsTrack'), 5000, 'error');
        return;
      }
      queueSongStar(track.id, false, track.serverId);
    },
    cli: { verb: 'unstar', description: 'unstar' },
  },
  'reload': {
    getLabel: t => t('settings.shortcutPlayPause'),
    runInMiniWindow: false,
    run: () => {
      const store = usePlayerStore.getState();
      const { currentTrack, stop, resetAudioPause, playTrack, initializeFromServerQueue } = store;
      stop();
      resetAudioPause();
      audioStop()
        .catch(() => {})
        .then(async () => {
          if (currentTrack) {
            try {
              const fresh = await getSong(currentTrack.id);
              const t = fresh ? songToTrack(fresh) : currentTrack;
              // No-arg queue: keep the canonical refs, re-bind the current track.
              playTrack(t, undefined, true);
            } catch {
              playTrack(currentTrack, undefined, true);
            }
          } else {
            await initializeFromServerQueue();
          }
        });
    },
    cli: { verb: 'reload', description: 'reload' },
  },
} as const satisfies Record<string, ShortcutActionMeta>;

export type ShortcutAction = keyof typeof SHORTCUT_ACTION_REGISTRY;
export type KeyAction = {
  [Action in ShortcutAction]: (typeof SHORTCUT_ACTION_REGISTRY)[Action] extends { inApp: ShortcutSlot } ? Action : never
}[ShortcutAction];
export type GlobalAction = {
  [Action in ShortcutAction]: (typeof SHORTCUT_ACTION_REGISTRY)[Action] extends { global: ShortcutSlot } ? Action : never
}[ShortcutAction];
