import Cookies from 'js-cookie'
import { setPreset, applyTheme } from '../services/style_setter/style_setter.js'
import messages from '../i18n/messages'
import localeService from '../services/locale/locale.service.js'

const BACKEND_LANGUAGE_COOKIE_NAME = 'userLanguage'

const browserLocale = (window.navigator.language || 'en').split('-')[0]

/* TODO this is a bit messy.
 * We need to declare settings with their types and also deal with
 * instance-default settings in some way, hopefully try to avoid copy-pasta
 * in general.
 */
export const multiChoiceProperties = [
  'postContentType',
  'subjectLineBehavior',
  'conversationDisplay', // tree | linear
  'conversationOtherRepliesButton', // below | inside
  'mentionLinkDisplay' // short | full_for_remote | full
]

export const defaultState = {
  profile: 'default',
  profileVersion: 0, // internal fe copy of server-side version
  expertLevel: 0, // used to track which settings to show and hide
  colors: {},
  theme: undefined,
  customTheme: undefined,
  customThemeSource: undefined,
  hideISP: false,
  hideInstanceWallpaper: false,
  // bad name: actually hides posts of muted USERS
  hideMutedPosts: undefined, // instance default
  hideMutedThreads: undefined, // instance default
  hideThreadsWithBlockedUsers: undefined, // instance default
  hideWordFilteredPosts: undefined, // instance default
  muteBotStatuses: undefined, // instance default
  collapseMessageWithSubject: true, // instance default
  padEmoji: true,
  showNavShortcuts: undefined, // instance default
  showPanelNavShortcuts: undefined, // instance default
  showWiderShortcuts: undefined, // instance default
  hideSiteFavicon: undefined, // instance default
  hideSiteName: undefined, // instance default
  hideAttachments: false,
  hideAttachmentsInConv: false,
  maxThumbnails: 16,
  hideNsfw: true,
  preloadImage: true,
  loopVideo: true,
  loopVideoSilentOnly: true,
  streaming: false,
  emojiReactionsOnTimeline: true,
  alwaysShowNewPostButton: false,
  autohideFloatingPostButton: false,
  pauseOnUnfocused: true,
  displayPageBackgrounds: true,
  centerAlignBio: true,
  compactUserInfo: false,
  stopGifs: undefined,
  replyVisibility: 'all',
  thirdColumnMode: 'notifications',
  notificationVisibility: {
    follows: true,
    mentions: true,
    likes: true,
    repeats: true,
    moves: true,
    emojiReactions: true,
    followRequest: true,
    polls: true
  },
  webPushNotifications: false,
  webPushHideIfCW: true,
  muteWords: [],
  highlight: {},
  interfaceLanguage: browserLocale,
  hideScopeNotice: false,
  useStreamingApi: false,
  deletePostsStreaming: true,
  sidebarRight: undefined, // instance default
  widenTimeline: undefined, // instance default
  subjectLineBehavior: undefined, // instance default
  alwaysShowSubjectInput: undefined, // instance default
  postContentType: undefined, // instance default
  // This hides statuses filtered via a word filter
  hideFilteredStatuses: undefined, // instance default
  modalOnRepeat: undefined, // instance default
  modalOnUnfollow: undefined, // instance default
  modalOnBlock: undefined, // instance default
  modalOnMute: undefined, // instance default
  modalOnDelete: undefined, // instance default
  modalOnLogout: undefined, // instance default
  modalOnApproveFollow: undefined, // instance default
  modalOnDenyFollow: undefined, // instance default
  modalOnSensitiveAttachmentWithoutCW: undefined, // instance default
  modalOnDirectPost: undefined, // instance default
  modalOnPrivatePost: undefined, // instance default
  modalOnUnlistedPost: undefined, // instance default
  modalOnPublicPost: undefined, // instance default
  modalOnLocalPost: undefined, // instance default
  playVideosInModal: false,
  useOneClickNsfw: false,
  useContainFit: true,
  disableStickyHeaders: false,
  showScrollbars: false,
  greentext: undefined, // instance default
  mentionLinkDisplay: undefined, // instance default
  mentionLinkShowTooltip: undefined, // instance default
  mentionLinkShowAvatar: undefined, // instance default
  mentionLinkFadeDomain: undefined, // instance default
  mentionLinkShowYous: undefined, // instance default
  mentionLinkBoldenYou: undefined, // instance default
  hidePostStats: undefined, // instance default
  hideBotIndication: undefined, // instance default
  hideUserStats: undefined, // instance default
  virtualScrolling: undefined, // instance default
  sensitiveByDefault: undefined, // instance default
  sensitiveIfSubject: undefined,
  soundOnNotif: false,
  soundOnNotifVolume: 0.2,
  soundOnNotifCustom: '',
  boostsFollowDefVis: false,
  searchPaginationLimit: 40,
  sillyFeatures: false,
  reactionsFilterItems: '',
  recurseSearch: false,
  recurseSearchLimit: 100,
  dedupeBoosts: true,
  showFaviconBadge: true,
  autoRefreshOnRequired: true,
  showUnreadInTitle: true,
  renderMisskeyMarkdown: undefined,
  renderMfmOnHover: undefined, // instance default
  conversationDisplay: undefined, // instance default
  conversationTreeAdvanced: undefined, // instance default
  conversationOtherRepliesButton: undefined, // instance default
  conversationTreeFadeAncestors: undefined, // instance default
  maxDepthInThread: undefined, // instance default
  translationLanguage: undefined, // instance default,
  postLanguage: undefined, // instance default,
  supportedTranslationLanguages: {}, // instance default
  userProfileDefaultTab: 'statuses',
  useBlurhash: true,
}

// caching the instance default properties
export const instanceDefaultProperties = Object.entries(defaultState)
  .filter(([key, value]) => value === undefined)
  .map(([key, value]) => key)

function updateLocalSettings(store, settingEntries, version = null) {
  if (version == null)
    version = store.state.profileVersion

  settingEntries.forEach(([name, value]) => {
    if (store.state[name] !== value) {
      store.dispatch('setOption', { name, value })
    }
  })

  // Set this at the end to override any potentially stored profileVersion
  store.commit('setOption', { name: 'profileVersion', value: version })
}


const config = {
  state: { ...defaultState },
  getters: {
    defaultConfig (state, getters, rootState, rootGetters) {
      const { instance } = rootState
      return {
        ...defaultState,
        ...Object.fromEntries(
          instanceDefaultProperties.map(key => [key, instance[key]])
        )
      }
    },
    mergedConfig (state, getters, rootState, rootGetters) {
      const { defaultConfig } = rootGetters
      return {
        ...defaultConfig,
        // Do not override with undefined
        ...Object.fromEntries(Object.entries(state).filter(([k, v]) => v !== undefined))
      }
    }
  },
  mutations: {
    setOption (state, { name, value }) {
      state[name] = value
    },
    setHighlight (state, { user, color, type }) {
      const data = this.state.config.highlight[user]
      if (color || type) {
        state.highlight[user] = { color: color || data.color, type: type || data.type }
      } else {
        delete state.highlight[user]
      }
    }
  },
  actions: {
    syncSettings: (store) => {
      store.commit('setOption', { name: 'profileVersion', value: store.state.profileVersion + 1 })
      const notice = {
        level: 'info',
        messageKey: 'settings_profile.synchronizing',
        messageArgs: { profile: store.state.profile },
        timeout: 5000
      }
      store.dispatch('pushGlobalNotice', notice)
      store.rootState.api.backendInteractor.saveSettingsProfile({
        settings: store.state, profileName: store.state.profile, version: store.state.profileVersion
      }).then(() => {
        store.dispatch('removeGlobalNotice', notice)
        store.dispatch('pushGlobalNotice', {
          level: 'success',
          messageKey: 'settings_profile.synchronized',
          messageArgs: { profile: store.state.profile },
          timeout: 2000
        })
        store.dispatch('listSettingsProfiles')
      }).catch((err) => {
        store.dispatch('removeGlobalNotice', notice)
        store.dispatch('pushGlobalNotice', {
          level: 'error',
          messageKey: 'settings_profile.synchronization_error',
          messageArgs: { error: err.message },
          timeout: 5000
        })
        console.error(err)
      })
    },
    deleteSettingsProfile (store, name) {
      store.rootState.api.backendInteractor.deleteSettingsProfile({ profileName: name }).then(() => {
        store.dispatch('listSettingsProfiles')
      })
    },
    loadSettings (store, data) {
      const knownKeys = new Set(Object.keys(defaultState))

      // Limit to supported properties
      const newSettingEntries =
         Object.entries(data)
        .filter(([key, value]) => knownKeys.has(key))

      // disregard stored profileVersion; sync afterwards increases previous version
      updateLocalSettings(store, newSettingEntries, null)
      store.dispatch('syncSettings')
    },
    setHighlight ({ commit, dispatch }, { user, color, type }) {
      commit('setHighlight', { user, color, type })
    },
    setOption ({ commit, dispatch }, { name, value, manual }) {
      commit('setOption', { name, value })
      if (manual === true) {
        dispatch('syncSettings')
      }
      switch (name) {
        case 'theme':
          setPreset(value)
          break
        case 'customTheme':
        case 'customThemeSource':
          applyTheme(value)
          break
        case 'interfaceLanguage':
          messages.setLanguage(this.getters.i18n, value)
          Cookies.set(BACKEND_LANGUAGE_COOKIE_NAME, localeService.internalToBackendLocale(value), {sameSite: 'Lax'})
          dispatch('setInstanceOption', { name: 'interfaceLanguage', value })
          break
        case 'thirdColumnMode':
          dispatch('setLayoutWidth', undefined)
          break
      }
    },
    getSettingsProfile (store, forceUpdate = false) {
      const profile = store.state.profile
      store.rootState.api.backendInteractor.getSettingsProfile({ store, profileName: profile })
        .then(({ settings, version }) => {
          console.log('found settings version', version)
          if (forceUpdate || (version > store.state.profileVersion)) {
            updateLocalSettings(store, Object.entries(settings), version)
          } else {
            console.log('settings are up to date')
          }
        })
        .catch((err) => {
          console.error(`could not fetch profile ${profile}`, err)
          if (err.statusCode === 404) {
            // create profile
            store.dispatch('pushGlobalNotice', {
              level: 'warning',
              messageKey: 'settings_profile.creating',
              messageArgs: { profile },
              timeout: 5000
            })
            store.dispatch('syncSettings')
          }
        })
    }
  }
}

export default config
