import {
  Action,
  SkinImages,
  Cursors,
  SkinRegion,
  GenLetterWidths,
  PlaylistStyle,
  SkinGenExColors,
  DummyVizData,
} from "../types";
import { createSelector } from "reselect";

import {
  CLOSE_WINAMP,
  OPEN_WINAMP,
  SET_SKIN_DATA,
  START_WORKING,
  STEP_MARQUEE,
  STOP_WORKING,
  TOGGLE_DOUBLESIZE_MODE,
  TOGGLE_LLAMA_MODE,
  TOGGLE_VISUALIZER_STYLE,
  SET_PLAYLIST_SCROLL_POSITION,
  LOADED,
  SET_Z_INDEX,
  DISABLE_MARQUEE,
  SET_DUMMY_VIZ_DATA,
  LOADING,
  LOAD_SERIALIZED_STATE,
  LOAD_DEFAULT_SKIN,
} from "../actionTypes";
import { DEFAULT_SKIN, VISUALIZER_ORDER } from "../constants";
import { DisplaySerializedStateV1 } from "../serializedStates/v1Types";

export interface DisplayState {
  visualizerStyle: number;
  doubled: boolean;
  llama: boolean;
  disableMarquee: boolean;
  marqueeStep: number;
  skinImages: SkinImages;
  skinCursors: Cursors | null;
  skinRegion: SkinRegion;
  skinGenLetterWidths: GenLetterWidths | null;
  skinColors: string[]; // Theoretically this could be a tuple of a specific length
  skinPlaylistStyle: PlaylistStyle | null;
  skinGenExColors: SkinGenExColors;
  working: boolean;
  closed: boolean;
  loading: boolean;
  playlistScrollPosition: number;
  zIndex: number;
  dummyVizData: DummyVizData | null;
}

const defaultSkinGenExColors = {
  itemBackground: "rgb(0,0,0)",
  itemForeground: "rgb(0,255,0)",
  windowBackground: "rgb(56,55,87)",
  buttonText: "rgb(57,57,66)",
  windowText: "rgb(255,255,255)",
  divider: "rgb(117,116,139)",
  playlistSelection: "rgb(0,0,198)",
  listHeaderBackground: "rgb(72,72,120)",
  listHeaderText: "rgb(255,255,255)",
  listHeaderFrameTopAndLeft: "rgb(108,108,180)",
  listHeaderFrameBottomAndRight: "rgb(36,36,60)",
  listHeaderFramePressed: "rgb(18,18,30)",
  listHeaderDeadArea: "rgb(36,36,60)",
  scrollbarOne: "rgb(36,36,60)",
  scrollbarTwo: "rgb(36,36,60)",
  pressedScrollbarOne: "rgb(121,130,150)",
  pressedScrollbarTwo: "rgb(78,88,110)",
  scrollbarDeadArea: "rgb(36,36,60)",
  listTextHighlighted: "rgb(0,198,255)",
  listTextHighlightedBackground: "rgb(0,198,255)",
  listTextSelected: "rgb(0,198,255)",
  listTextSelectedBackground: "rgb(0,198,255)",
};

const defaultDisplayState = {
  doubled: false,
  marqueeStep: 0,
  disableMarquee: false,
  loading: true,
  llama: false,
  closed: false,
  working: false,
  skinImages: DEFAULT_SKIN.images,
  skinColors: DEFAULT_SKIN.colors,
  skinCursors: null,
  skinPlaylistStyle: null,
  skinRegion: {},
  visualizerStyle: 0, // Index into VISUALIZER_ORDER
  dummyVizData: null,
  playlistScrollPosition: 0,
  skinGenLetterWidths: null, // TODO: Get the default value for this?
  skinGenExColors: defaultSkinGenExColors,
  additionalVisualizers: [],
  zIndex: 0,
};

const display = (
  state: DisplayState = defaultDisplayState,
  action: Action
): DisplayState => {
  switch (action.type) {
    case LOAD_DEFAULT_SKIN:
      const {
        skinImages,
        skinColors,
        skinCursors,
        skinPlaylistStyle,
        skinRegion,
        skinGenLetterWidths,
        skinGenExColors,
      } = defaultDisplayState;
      return {
        ...state,
        skinImages,
        skinColors,
        skinCursors,
        skinPlaylistStyle,
        skinRegion,
        skinGenLetterWidths,
        skinGenExColors,
      };

    case TOGGLE_DOUBLESIZE_MODE:
      return { ...state, doubled: !state.doubled };
    case TOGGLE_LLAMA_MODE:
      return { ...state, llama: !state.llama };
    case STEP_MARQUEE:
      return state.disableMarquee
        ? state
        : { ...state, marqueeStep: state.marqueeStep + 1 };
    case DISABLE_MARQUEE:
      return { ...state, disableMarquee: true };
    case STOP_WORKING:
      return { ...state, working: false };
    case START_WORKING:
      return { ...state, working: true };
    case CLOSE_WINAMP:
      return { ...state, closed: true };
    case OPEN_WINAMP:
      return { ...state, closed: false };
    case LOADING:
      return { ...state, loading: true };
    case LOADED:
      return { ...state, loading: false };
    case SET_SKIN_DATA:
      const { data } = action;
      return {
        ...state,
        loading: false,
        skinImages: data.skinImages,
        skinColors: data.skinColors,
        skinPlaylistStyle: data.skinPlaylistStyle,
        skinCursors: data.skinCursors,
        skinRegion: data.skinRegion,
        skinGenLetterWidths: data.skinGenLetterWidths,
        skinGenExColors: data.skinGenExColors || defaultSkinGenExColors,
      };
    case TOGGLE_VISUALIZER_STYLE:
      return {
        ...state,
        visualizerStyle: (state.visualizerStyle + 1) % VISUALIZER_ORDER.length,
      };
    case SET_PLAYLIST_SCROLL_POSITION:
      return { ...state, playlistScrollPosition: action.position };
    case SET_Z_INDEX:
      return { ...state, zIndex: action.zIndex };
    case SET_DUMMY_VIZ_DATA:
      return { ...state, dummyVizData: action.data };
    case LOAD_SERIALIZED_STATE:
      return { ...state, ...action.serializedState.display };
    default:
      return state;
  }
};
export default display;

export const getSerializedState = (
  state: DisplayState
): DisplaySerializedStateV1 => {
  // My kingdom for a type-safe `_.pick`.
  const {
    visualizerStyle,
    doubled,
    llama,
    marqueeStep,
    skinImages,
    skinCursors,
    skinRegion,
    skinGenLetterWidths,
    skinColors,
    skinPlaylistStyle,
  } = state;
  return {
    visualizerStyle,
    doubled,
    llama,
    marqueeStep,
    skinImages,
    skinCursors,
    skinRegion,
    skinGenLetterWidths,
    skinColors,
    skinPlaylistStyle,
  };
};

export const getVisualizerStyle = createSelector(
  (state: DisplayState) => state.visualizerStyle,
  (visualizationStyle): string => {
    return VISUALIZER_ORDER[visualizationStyle];
  }
);
