/**
 * Auth Service - UUID-based anonymous authentication
 * 
 * No email addresses, no personal data
 * User remembers only their UUID
 * Email stored in Directus is hash(uuid)@domain - UUID cannot be recovered
 */

import { directus } from './directus.js'
import { i18n } from '../i18n.js'

const AUTH_DOMAIN = 'dgray.io'

class AuthService {
    constructor() {
        this.currentUser = null
        this.listeners = new Set()
        this.hashCache = new Map()
    }

    /**
     * Generates a new UUID for account creation
     * @returns {string} UUID v4
     */
    generateUuid() {
        if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {
            return crypto.randomUUID()
        }
        
        return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
            const r = Math.random() * 16 | 0
            const v = c === 'x' ? r : (r & 0x3 | 0x8)
            return v.toString(16)
        })
    }

    /**
     * Hashes a string using SHA-256
     * @param {string} str - String to hash
     * @returns {Promise<string>} Hex-encoded hash
     */
    async hashString(str) {
        if (this.hashCache.has(str)) {
            return this.hashCache.get(str)
        }
        
        const encoder = new TextEncoder()
        const data = encoder.encode(str)
        const hashBuffer = await crypto.subtle.digest('SHA-256', data)
        const hashArray = Array.from(new Uint8Array(hashBuffer))
        const hash = hashArray.map(b => b.toString(16).padStart(2, '0')).join('')
        
        this.hashCache.set(str, hash)
        return hash
    }

    /**
     * Converts UUID to hashed email for Directus
     * The UUID cannot be recovered from the hash
     * @param {string} uuid - User UUID
     * @returns {Promise<string>} Hashed email address
     */
    async uuidToEmail(uuid) {
        const hash = await this.hashString(uuid)
        return `${hash.substring(0, 32)}@${AUTH_DOMAIN}`
    }

    /**
     * Creates a new anonymous account
     * @returns {Promise<{uuid: string, success: boolean, error?: string}>}
     */
    async createAccount() {
        const uuid = this.generateUuid()
        const email = await this.uuidToEmail(uuid)

        try {
            await directus.register(email, uuid)
            
            const loginResult = await this.login(uuid)
            
            if (!loginResult.success) {
                return { 
                    uuid, 
                    success: true, 
                    pendingVerification: true,
                    message: 'Account created. Login may require activation.'
                }
            }

            return { uuid, success: true }
        } catch (error) {
            console.error('Registration failed:', error)
            return { 
                uuid: null, 
                success: false, 
                error: error.message || 'Registration failed' 
            }
        }
    }

    /**
     * Logs in with UUID
     * @param {string} uuid - User UUID
     * @returns {Promise<{success: boolean, error?: string}>}
     */
    async login(uuid) {
        const email = await this.uuidToEmail(uuid)

        try {
            await directus.login(email, uuid)
            this.currentUser = await directus.getCurrentUser()
            this.notifyListeners()
            this.storeUuid(uuid)

            return { success: true }
        } catch (error) {
            console.error('Login failed:', error)
            return { 
                success: false, 
                error: error.message || 'Invalid UUID' 
            }
        }
    }

    /**
     * Logs out the current user and resets preferences to defaults
     */
    async logout() {
        try {
            await directus.logout()
        } catch (e) {
            // Ignore errors
        }
        
        this.currentUser = null
        this.clearStoredUuid()
        this.resetPreferencesToDefaults()
        this.notifyListeners()
    }

    /**
     * Reset preferences to defaults on logout
     */
    resetPreferencesToDefaults() {
        const defaultCurrency = 'USD'
        const defaultLocale = 'en'
        
        localStorage.setItem('dgray_currency', defaultCurrency)
        localStorage.setItem('locale', defaultLocale)
        
        window.dispatchEvent(new CustomEvent('currency-changed', { detail: { currency: defaultCurrency } }))
        i18n.setLocale(defaultLocale)
    }

    /**
     * Checks if user is logged in
     * @returns {boolean}
     */
    isLoggedIn() {
        return directus.isAuthenticated()
    }

    /**
     * Gets current user data
     * @returns {Promise<Object|null>}
     */
    async getUser() {
        if (!this.isLoggedIn()) return null

        if (!this.currentUser) {
            try {
                this.currentUser = await directus.getCurrentUser()
                // Sync preferences to localStorage
                this.syncPreferencesToLocal()
            } catch (e) {
                return null
            }
        }

        return this.currentUser
    }

    /**
     * Sync user preferences from Directus to localStorage and apply them
     */
    syncPreferencesToLocal() {
        if (!this.currentUser) return
        
        if (this.currentUser.preferred_currency) {
            const currency = this.currentUser.preferred_currency
            localStorage.setItem('dgray_currency', currency)
            window.dispatchEvent(new CustomEvent('currency-changed', { detail: { currency } }))
        }
        if (this.currentUser.preferred_locale) {
            const locale = this.currentUser.preferred_locale
            localStorage.setItem('locale', locale)
            i18n.setLocale(locale)
        }
    }

    /**
     * Update user preferences in Directus
     * @param {Object} prefs - Preferences to update
     * @param {string} [prefs.preferred_currency] - Currency code
     * @param {string} [prefs.preferred_locale] - Locale code
     * @returns {Promise<boolean>} Success
     */
    async updatePreferences(prefs) {
        if (!this.isLoggedIn()) return false
        
        try {
            await directus.updateCurrentUser(prefs)
            // Update local cache
            this.currentUser = { ...this.currentUser, ...prefs }
            return true
        } catch (e) {
            console.error('Failed to update preferences:', e)
            return false
        }
    }

    /**
     * Stores UUID in localStorage (optional convenience)
     * User should still backup their UUID
     * @param {string} uuid 
     */
    storeUuid(uuid) {
        localStorage.setItem('dgray_uuid', uuid)
    }

    /**
     * Gets stored UUID if available
     * @returns {string|null}
     */
    getStoredUuid() {
        return localStorage.getItem('dgray_uuid')
    }

    /**
     * Clears stored UUID
     */
    clearStoredUuid() {
        localStorage.removeItem('dgray_uuid')
    }

    /**
     * Subscribe to auth state changes
     * @param {Function} callback 
     * @returns {Function} Unsubscribe function
     */
    subscribe(callback) {
        this.listeners.add(callback)
        return () => this.listeners.delete(callback)
    }

    /**
     * Notifies all listeners of auth state change
     */
    notifyListeners() {
        this.listeners.forEach(cb => cb(this.isLoggedIn(), this.currentUser))
    }

    /**
     * Tries to restore session from stored tokens
     */
    async tryRestoreSession() {
        if (directus.isAuthenticated()) {
            try {
                this.currentUser = await directus.getCurrentUser()
                this.syncPreferencesToLocal()
                this.notifyListeners()
                return true
            } catch (e) {
                directus.clearTokens()
                return false
            }
        }
        return false
    }
}

export const auth = new AuthService()
export default auth
