import { ServiceBase } from '@/services/ServiceBase'
import { useAuthStore } from '@/stores/auth'
import { storeToRefs } from 'pinia'
import { NetworkService } from '@/services/NetworkService'
import dayjs from 'dayjs'
import { PersistenceService } from './PersistenceService'

export class AuthenticationService extends ServiceBase {
  private networkService = new NetworkService()
  private auth = useAuthStore()
  private persistanceService: PersistenceService = PersistenceService.getInstance()

  isAuthenticated() {
    const auth = useAuthStore()
    const { isLoggedIn } = storeToRefs(auth)
    return isLoggedIn
  }

  async login(username: string, password: string) {
    const response = await this.networkService.post({
      uri: '/login',
      body: { username, password },
    })
    const { token, refreshToken } = response
    this.persist(token)
    this.persistRefreshToken(refreshToken)
    return token
  }

  async logout() {
    this.removePersistence()
  }

  removePersistence() {
    const { clearUser, clearToken, clearRefreshToken } = this.auth
    clearToken()
    clearUser()
    clearRefreshToken()
    this.persistanceService.clearTokens()
  }

  async persist(jwt: string) {
    const { setToken, setUser } = this.auth
    const { user: loggedUser } = this.parseJwt(jwt)
    setToken(jwt)
    setUser(loggedUser)
    try {
      await this.persistanceService.saveToken(jwt)
    } catch (error) {
      this.logger.error(error, 'Error saving token')
    }
  }

  persistRefreshToken(jwt: string) {
    const { setRefreshToken } = this.auth
    setRefreshToken(jwt)
    try {
      this.persistanceService.saveRefreshToken(jwt)
    } catch (error) {
      this.logger.error(error, 'Error saving refresh token')
    }
  }

  private parseJwt(token: string) {
    if (!token) {
      return
    }
    const base64Url = token.split('.')[1] ?? ''
    const base64 = base64Url.replace('-', '+').replace('_', '/')
    return JSON.parse(window.atob(base64))
  }

  async fromStorage() {
    console.log('fromStorage')
    const auth = useAuthStore()
    const { setToken, setRefreshToken, setUser } = auth
    const token = await this.persistanceService.readToken()
    const refreshToken = await this.persistanceService.readRefreshToken()

    if (token && refreshToken) {
      try {
        const { user: parsed } = this.parseJwt(token)
        const isAfter = dayjs().isAfter(parsed.exp * 1000)
        if (isAfter) {
          this.removePersistence()
          return
        }
        setToken(token)
        setRefreshToken(refreshToken)
        setUser(parsed)
        this.logger.debug('Token loaded from storage', parsed)
      } catch (error) {
        this.logger.error(error, 'Error parsing token')
        this.removePersistence()
      }
    } else {
      this.removePersistence()
    }
  }

  hasRoles(rolesToCheck: string[]) {
    const auth = useAuthStore()
    const { roles } = storeToRefs(auth)
    return roles.value.some((role) => rolesToCheck.includes(role))
  }
}
