import { defineStore } from 'pinia'

import { AUTH_TOKEN_KEY, api } from '../lib/api'
import { ApiRequestError } from '../lib/http'
import type {
  AuthSession,
  ChangePasswordPayload,
  DemoLoginPayload,
  LoginPayload,
  TeamLoginPayload,
  TwitchAuthorizePayload,
} from '../types/awards'

const adminAccessRoles = new Set(['member', 'reviewer', 'organization_team', 'content_admin', 'admin', 'owner', 'creator'])
const contentManageRoles = new Set(['content_admin', 'admin', 'owner', 'creator'])
const adminWorkspaceRoles = new Set(['admin', 'owner', 'creator'])
const adminWorkspacePermissions = new Set([
  'dashboard',
  'years',
  'nominations',
  'categories',
  'candidates',
  'clips',
  'risk',
  'audit',
  'analytics',
  'voting',
  'winners',
])

function hasEffectivePermission(permissionKeys: string[] = [], permissionKey: string) {
  if (permissionKeys.includes(permissionKey)) {
    return true
  }

  if (permissionKey === 'voting') {
    return permissionKeys.includes('analytics') || permissionKeys.includes('winners')
  }

  return false
}

function readStoredToken() {
  if (typeof window === 'undefined') return null
  return window.localStorage.getItem(AUTH_TOKEN_KEY)
}

function writeStoredToken(token: string | null) {
  if (typeof window === 'undefined') return

  if (token) {
    window.localStorage.setItem(AUTH_TOKEN_KEY, token)
  } else {
    window.localStorage.removeItem(AUTH_TOKEN_KEY)
  }
}

export const useAuthStore = defineStore('auth', {
  state: () => ({
    session: null as AuthSession | null,
    hydrated: false,
    loading: false,
  }),
  getters: {
    isLoggedIn: (state) => Boolean(state.session),
    isAdmin: (state) => adminAccessRoles.has(state.session?.role ?? ''),
    canAccessAdmin: (state) => adminAccessRoles.has(state.session?.role ?? ''),
    canManageContent: (state) => contentManageRoles.has(state.session?.role ?? '') || (state.session?.permissionKeys ?? []).includes('content'),
    canManageAdminWorkspace: (state) => adminWorkspaceRoles.has(state.session?.role ?? '') || (state.session?.permissionKeys ?? []).some((key) => adminWorkspacePermissions.has(key)),
    canManageOperationalSettings: (state) => state.session?.role === 'owner' || state.session?.role === 'creator',
    canManageTeam: (state) => (state.session?.permissionKeys ?? []).includes('team'),
    hasPermission: (state) => (permissionKey: string) => hasEffectivePermission(state.session?.permissionKeys ?? [], permissionKey),
    isOwner: (state) => state.session?.role === 'owner',
    isCreator: (state) => state.session?.role === 'creator',
    isOwnerOrCreator: (state) => state.session?.role === 'owner' || state.session?.role === 'creator',
    isTeamSession: (state) => Boolean(state.session?.teamLogin),
  },
  actions: {
    clearSession() {
      this.session = null
      writeStoredToken(null)
    },
    async hydrate() {
      if (!readStoredToken()) {
        this.session = null
        this.hydrated = true
        return
      }

      try {
        this.session = await api.getSession()
      } catch (error) {
        if (error instanceof ApiRequestError && (error.status === 401 || error.status === 403)) {
          this.clearSession()
        }
      } finally {
        this.hydrated = true
      }
    },
    async login(payload: LoginPayload) {
      this.loading = true
      try {
        const session = await api.login(payload)
        this.session = session
        writeStoredToken(session.sessionToken)
      } finally {
        this.loading = false
      }
    },
    async demoLogin(payload: DemoLoginPayload) {
      this.loading = true
      try {
        const session = await api.demoLogin(payload)
        this.session = session
        writeStoredToken(session.sessionToken)
      } finally {
        this.loading = false
      }
    },
    async teamLogin(payload: TeamLoginPayload) {
      this.loading = true
      try {
        const session = await api.teamLogin(payload)
        this.session = session
        writeStoredToken(session.sessionToken)
      } finally {
        this.loading = false
      }
    },
    async changePassword(payload: ChangePasswordPayload) {
      this.loading = true
      try {
        const session = await api.changePassword(payload)
        this.session = session
        writeStoredToken(session.sessionToken)
      } finally {
        this.loading = false
      }
    },
    async startTwitchAuthorization(payload: Omit<TwitchAuthorizePayload, 'frontendOrigin'>) {
      this.loading = true
      try {
        const response = await api.startTwitchAuthorization({
          ...payload,
          frontendOrigin: window.location.origin,
        })
        window.location.assign(response.authorizationUrl)
      } finally {
        this.loading = false
      }
    },
    async disconnectTwitchBinding() {
      this.loading = true
      try {
        const response = await api.disconnectTwitchBinding()
        this.session = response.session
        writeStoredToken(response.session?.sessionToken ?? null)
        return response
      } finally {
        this.loading = false
      }
    },
    async completeOAuthSession(sessionToken: string) {
      this.loading = true
      try {
        writeStoredToken(sessionToken)
        this.session = await api.getSession()
        this.hydrated = true
      } catch (error) {
        writeStoredToken(null)
        this.session = null
        throw error
      } finally {
        this.loading = false
      }
    },
    async logout() {
      this.loading = true
      try {
        await api.logout()
      } finally {
        this.clearSession()
        this.loading = false
      }
    },
    async deleteMyData() {
      this.loading = true
      try {
        const result = await api.deleteMyData()
        this.clearSession()
        return result
      } finally {
        this.loading = false
      }
    },
  },
})

export type AuthStore = ReturnType<typeof useAuthStore>
