import { defineStore } from 'pinia'
import { io, Socket } from 'socket.io-client'
import type { AssetDataT, Character, Notification, User, WorldSettings } from '@/types'
import config from '@/config'
import { useCookies } from '@vueuse/integrations/useCookies'
import { getDomain } from '@/utilities'

export const useGameStore = defineStore('game', {
  state: () => {
    return {
      notifications: [] as Notification[],
      token: '' as string | null,
      connection: null as Socket | null,
      user: null as User | null,
      character: null as Character | null,
      world: {
        date: new Date(),
        isRainEnabled: false,
        isFogEnabled: false,
        fogDensity: 0.5
      } as WorldSettings,
      game: {
        isLoading: false,
        isLoaded: false, // isLoaded is currently being used to determine if the player has interacted with the game
        loadedAssets: [] as AssetDataT[],
        isPlayerDraggingCamera: false,
        isCameraFollowingCharacter: false
      },
      uiSettings: {
        isChatOpen: false,
        isCharacterProfileOpen: false,
        isGmPanelOpen: false
      }
    }
  },
  getters: {
    getLoadedAssets: (state) => {
      return state.game.loadedAssets
    },
    getLoadedAsset: (state) => {
      return (key: string | undefined) => {
        if (!key) return null
        return state.game.loadedAssets.find((asset) => asset.key === key)
      }
    },
    getLoadedAssetsByGroup: (state) => {
      return (group: string) => state.game.loadedAssets.filter((asset) => asset.group === group)
    }
  },
  actions: {
    addNotification(notification: Notification) {
      if (!notification.id) {
        notification.id = Math.random().toString(16)
      }
      this.notifications.push(notification)
    },
    removeNotification(id: string) {
      this.notifications = this.notifications.filter((notification: Notification) => notification.id !== id)
    },
    setToken(token: string) {
      this.token = token
    },
    setUser(user: User | null) {
      this.user = user
    },
    setCharacter(character: Character | null) {
      this.character = character
    },
    toggleGmPanel() {
      this.uiSettings.isGmPanelOpen = !this.uiSettings.isGmPanelOpen
    },
    setPlayerDraggingCamera(moving: boolean) {
      this.game.isPlayerDraggingCamera = moving
    },
    toggleChat() {
      this.uiSettings.isChatOpen = !this.uiSettings.isChatOpen
    },
    toggleCharacterProfile() {
      this.uiSettings.isCharacterProfileOpen = !this.uiSettings.isCharacterProfileOpen
    },
    initConnection() {
      this.connection = io(config.server_endpoint, {
        secure: !config.development,
        withCredentials: true,
        transports: ['websocket'],
        reconnectionAttempts: 5
      })

      // #99 - If we can't connect, disconnect
      this.connection.on('connect_error', () => {
        this.disconnectSocket()
      })

      // Let the server know the user is logged in
      this.connection.emit('login')

      // set user
      this.connection.on('logged_in', (user: User) => {
        this.setUser(user)
      })

      // When we can't reconnect, disconnect
      this.connection.on('reconnect_failed', () => {
        this.disconnectSocket()
      })
    },
    disconnectSocket() {
      this.connection?.disconnect()

      useCookies().remove('token', {
        domain: getDomain()
      })

      this.connection = null
      this.token = null
      this.user = null
      this.character = null

      this.game.isLoaded = false
      this.game.loadedAssets = []
      this.game.isPlayerDraggingCamera = false
      this.game.isCameraFollowingCharacter = false

      this.uiSettings.isChatOpen = false
      this.uiSettings.isCharacterProfileOpen = false
      this.uiSettings.isGmPanelOpen = false

      this.world.date = new Date()
      this.world.isRainEnabled = false
      this.world.isFogEnabled = false
      this.world.fogDensity = 0.5
    }
  }
})
