/**
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * @format
 */

import {remote} from 'electron';
import uuidv1 from 'uuid/v1';
import {ReactElement} from 'react';
import CancellableExportStatus from '../chrome/CancellableExportStatus';
import {Actions} from './';
export const ACTIVE_SHEET_PLUGIN_SHEET: 'PLUGIN_SHEET' = 'PLUGIN_SHEET';
export const ACTIVE_SHEET_BUG_REPORTER: 'BUG_REPORTER' = 'BUG_REPORTER';
export const ACTIVE_SHEET_PLUGINS: 'PLUGINS' = 'PLUGINS';
export const ACTIVE_SHEET_SELECT_PLUGINS_TO_EXPORT: 'SELECT_PLUGINS_TO_EXPORT' =
  'SELECT_PLUGINS_TO_EXPORT';
export const ACTIVE_SHEET_SHARE_DATA: 'SHARE_DATA' = 'SHARE_DATA';
export const ACTIVE_SHEET_SIGN_IN: 'SIGN_IN' = 'SIGN_IN';
export const ACTIVE_SHEET_SETTINGS: 'SETTINGS' = 'SETTINGS';
export const ACTIVE_SHEET_SHARE_DATA_IN_FILE: 'SHARE_DATA_IN_FILE' =
  'SHARE_DATA_IN_FILE';
export const SET_EXPORT_STATUS_MESSAGE: 'SET_EXPORT_STATUS_MESSAGE' =
  'SET_EXPORT_STATUS_MESSAGE';
export const UNSET_SHARE: 'UNSET_SHARE' = 'UNSET_SHARE';

export type ActiveSheet =
  | typeof ACTIVE_SHEET_PLUGIN_SHEET
  | typeof ACTIVE_SHEET_BUG_REPORTER
  | typeof ACTIVE_SHEET_PLUGINS
  | typeof ACTIVE_SHEET_SHARE_DATA
  | typeof ACTIVE_SHEET_SIGN_IN
  | typeof ACTIVE_SHEET_SETTINGS
  | typeof ACTIVE_SHEET_SHARE_DATA_IN_FILE
  | typeof ACTIVE_SHEET_SELECT_PLUGINS_TO_EXPORT
  | null;

export type LauncherMsg = {
  message: string;
  severity: 'warning' | 'error';
};
export type ServerPorts = {
  insecure: number;
  secure: number;
};

export type StatusMessageType = {
  msg: string;
  sender: string;
};

type SubShareType =
  | {
      type: 'file';
      file: string;
    }
  | {
      type: 'link';
      url?: string;
    };

export type ShareType = {
  statusComponent?: React.ReactNode;
  closeOnFinish: boolean;
} & SubShareType;

export type NTUsersFormData = {
  flipper_trace: string | null;
};

export type State = {
  leftSidebarVisible: boolean;
  rightSidebarVisible: boolean;
  rightSidebarAvailable: boolean;
  windowIsFocused: boolean;
  activeSheet: ActiveSheet;
  share: ShareType | null;
  sessionId: string | null;
  serverPorts: ServerPorts;
  downloadingImportData: boolean;
  launcherMsg: LauncherMsg;
  flipperRating: number | null;
  statusMessages: Array<string>;
  xcodeCommandLineToolsDetected: boolean;
  supportForm: {webState: NTUsersFormData} | null;
};

type BooleanActionType =
  | 'leftSidebarVisible'
  | 'rightSidebarVisible'
  | 'rightSidebarAvailable'
  | 'windowIsFocused'
  | 'downloadingImportData';

export type Action =
  | {
      type: BooleanActionType;
      payload?: boolean;
    }
  | {
      type: 'SET_ACTIVE_SHEET';
      payload: ActiveSheet;
    }
  | {
      type: typeof ACTIVE_SHEET_SHARE_DATA_IN_FILE;
      payload: {file: string; closeOnFinish: boolean};
    }
  | {
      type: typeof ACTIVE_SHEET_SELECT_PLUGINS_TO_EXPORT;
      payload: ShareType;
    }
  | {
      type: 'SET_SERVER_PORTS';
      payload: {
        insecure: number;
        secure: number;
      };
    }
  | {
      type: 'LAUNCHER_MSG';
      payload: {
        severity: 'warning' | 'error';
        message: string;
      };
    }
  | {
      type: 'SET_FLIPPER_RATING';
      payload: {
        rating: number;
      };
    }
  | {
      type: 'UNSET_SHARE';
    }
  | {
      type: 'SET_EXPORT_STATUS_MESSAGE';
      payload: React.ReactNode;
    }
  | {
      type: 'SET_EXPORT_URL';
      payload: string;
    }
  | {
      type: 'ADD_STATUS_MSG';
      payload: {msg: string; sender: string};
    }
  | {
      type: 'REMOVE_STATUS_MSG';
      payload: {msg: string; sender: string};
    }
  | {
      type: 'SET_XCODE_DETECTED';
      payload: {
        isDetected: boolean;
      };
    }
  | {
      type: 'SET_SUPPORT_FORM_STATE';
      payload: {
        webState: NTUsersFormData;
      } | null;
    };

export const initialState: () => State = () => ({
  leftSidebarVisible: true,
  rightSidebarVisible: true,
  rightSidebarAvailable: false,
  windowIsFocused: remote.getCurrentWindow().isFocused(),
  activeSheet: null,
  share: null,
  sessionId: uuidv1(),
  serverPorts: {
    insecure: 8089,
    secure: 8088,
  },
  downloadingImportData: false,
  launcherMsg: {
    severity: 'warning',
    message: '',
  },
  flipperRating: null,
  statusMessages: [],
  xcodeCommandLineToolsDetected: false,
  supportForm: null,
});

function statusMessage(sender: string, msg: string): string {
  const messageTrimmed = msg.trim();
  const senderTrimmed = sender.trim();
  let statusMessage = senderTrimmed.length > 0 ? senderTrimmed : '';
  statusMessage =
    statusMessage.length > 0 && messageTrimmed.length > 0
      ? `${statusMessage}: ${messageTrimmed}`
      : '';
  return statusMessage;
}

export default function reducer(
  state: State | undefined,
  action: Actions,
): State {
  state = state || initialState();
  if (
    action.type === 'leftSidebarVisible' ||
    action.type === 'rightSidebarVisible' ||
    action.type === 'rightSidebarAvailable' ||
    action.type === 'windowIsFocused' ||
    action.type === 'downloadingImportData'
  ) {
    const newValue =
      typeof action.payload === 'undefined'
        ? !state[action.type]
        : action.payload;

    if (state[action.type] === newValue) {
      // value hasn't changed
      return state;
    } else {
      return {
        ...state,
        [action.type]: newValue,
      };
    }
  } else if (action.type === 'SET_ACTIVE_SHEET') {
    return {
      ...state,
      activeSheet: action.payload,
    };
  } else if (action.type === ACTIVE_SHEET_SHARE_DATA_IN_FILE) {
    return {
      ...state,
      activeSheet: ACTIVE_SHEET_SHARE_DATA_IN_FILE,
      share: {
        type: 'file',
        file: action.payload.file,
        closeOnFinish: action.payload.closeOnFinish,
      },
    };
  } else if (action.type === ACTIVE_SHEET_SELECT_PLUGINS_TO_EXPORT) {
    return {
      ...state,
      activeSheet: ACTIVE_SHEET_SELECT_PLUGINS_TO_EXPORT,
      share: action.payload,
    };
  } else if (action.type === 'SET_SERVER_PORTS') {
    return {
      ...state,
      serverPorts: action.payload,
    };
  } else if (action.type === 'LAUNCHER_MSG') {
    return {
      ...state,
      launcherMsg: action.payload,
    };
  } else if (action.type === 'SET_FLIPPER_RATING') {
    return {
      ...state,
      flipperRating: action.payload.rating,
    };
  } else if (action.type === 'SET_EXPORT_STATUS_MESSAGE') {
    if (state.share) {
      const {share} = state;
      return {
        ...state,
        share: {...share, statusComponent: action.payload},
      };
    }
    return state;
  } else if (action.type === 'UNSET_SHARE') {
    return {...state, share: null};
  } else if (action.type === 'SET_EXPORT_URL') {
    const share = state.share;
    if (share && share.type === 'link') {
      return {...state, share: {...share, url: action.payload}};
    }
    return state;
  } else if (action.type === 'ADD_STATUS_MSG') {
    const {sender, msg} = action.payload;
    const statusMsg = statusMessage(sender, msg);
    if (statusMsg.length > 0) {
      return {
        ...state,
        statusMessages: [...state.statusMessages, statusMsg],
      };
    }
    return state;
  } else if (action.type === 'REMOVE_STATUS_MSG') {
    const {sender, msg} = action.payload;
    const statusMsg = statusMessage(sender, msg);
    if (statusMsg.length > 0) {
      const statusMessages = [...state.statusMessages];
      statusMessages.splice(statusMessages.indexOf(statusMsg), 1);
      return {...state, statusMessages};
    }
    return state;
  } else if (action.type === 'SET_XCODE_DETECTED') {
    return {...state, xcodeCommandLineToolsDetected: action.payload.isDetected};
  } else if (action.type === 'SET_SUPPORT_FORM_STATE') {
    return {...state, supportForm: action.payload};
  } else {
    return state;
  }
}

export const toggleAction = (
  type: BooleanActionType,
  payload?: boolean,
): Action => ({
  type,
  payload,
});

export const unsetShare = (): Action => ({
  type: UNSET_SHARE,
});

export const setExportStatusComponent = (
  payload: ReactElement<typeof CancellableExportStatus>,
): Action => ({
  type: SET_EXPORT_STATUS_MESSAGE,
  payload,
});

export const setSelectPluginsToExportActiveSheet = (
  payload: ShareType,
): Action => ({
  type: ACTIVE_SHEET_SELECT_PLUGINS_TO_EXPORT,
  payload,
});

export const setExportDataToFileActiveSheet = (payload: {
  file: string;
  closeOnFinish: boolean;
}): Action => ({
  type: ACTIVE_SHEET_SHARE_DATA_IN_FILE,
  payload: payload,
});

export const setActiveSheet = (payload: ActiveSheet): Action => ({
  type: 'SET_ACTIVE_SHEET',
  payload,
});

export const toggleLeftSidebarVisible = (payload?: boolean): Action => ({
  type: 'leftSidebarVisible',
  payload,
});

export const toggleRightSidebarVisible = (payload?: boolean): Action => ({
  type: 'rightSidebarVisible',
  payload,
});

export const toggleRightSidebarAvailable = (payload?: boolean): Action => ({
  type: 'rightSidebarAvailable',
  payload,
});

export const setFlipperRating = (rating: number): Action => ({
  type: 'SET_FLIPPER_RATING',
  payload: {
    rating,
  },
});

export const setExportURL = (result: string): Action => ({
  type: 'SET_EXPORT_URL',
  payload: result,
});

export const addStatusMessage = (payload: StatusMessageType): Action => ({
  type: 'ADD_STATUS_MSG',
  payload,
});

export const removeStatusMessage = (payload: StatusMessageType): Action => ({
  type: 'REMOVE_STATUS_MSG',
  payload,
});

export const setXcodeDetected = (isDetected: boolean): Action => ({
  type: 'SET_XCODE_DETECTED',
  payload: {isDetected},
});

export const setSupportFormState = (
  payload: {webState: NTUsersFormData} | null,
): Action => ({
  type: 'SET_SUPPORT_FORM_STATE',
  payload,
});
