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

const ANON_KEY = 'dgray_favorites'

class FavoritesService {
    constructor() {
        this.ids = new Set()
        this.loaded = false
        this.syncing = false
        this.listeners = []
    }

    init() {
        // Migrate old localStorage key
        const oldFavs = localStorage.getItem('favorites')
        if (oldFavs && !localStorage.getItem(ANON_KEY)) {
            localStorage.setItem(ANON_KEY, oldFavs)
            localStorage.removeItem('favorites')
        }

        this.ids = new Set(this.getAnonIds())
        this.loaded = true

        auth.subscribe((loggedIn) => {
            if (loggedIn) {
                this.mergeOnLogin()
            } else {
                this.saveAnonIds()
                this.loaded = true
                this.notify()
            }
        })

        if (auth.isLoggedIn()) {
            this.mergeOnLogin()
        }
    }

    subscribe(cb) {
        this.listeners.push(cb)
        return () => {
            this.listeners = this.listeners.filter(l => l !== cb)
        }
    }

    notify() {
        this.listeners.forEach(cb => cb(this.ids))
        window.dispatchEvent(new CustomEvent('favorites-changed'))
    }

    // localStorage helpers
    getAnonIds() {
        try {
            return JSON.parse(localStorage.getItem(ANON_KEY) || '[]')
        } catch {
            return []
        }
    }

    saveAnonIds() {
        localStorage.setItem(ANON_KEY, JSON.stringify([...this.ids]))
    }

    // Public API
    isFavorite(id) {
        return this.ids.has(id)
    }

    getAll() {
        return [...this.ids]
    }

    async toggle(id) {
        const wasFavorite = this.ids.has(id)

        // Optimistic update
        if (wasFavorite) {
            this.ids.delete(id)
        } else {
            this.ids.add(id)
        }
        this.notify()

        if (auth.isLoggedIn()) {
            try {
                if (wasFavorite) {
                    await this.removeRemote(id)
                } else {
                    await this.addRemote(id)
                }
            } catch (e) {
                // Revert on failure
                if (wasFavorite) {
                    this.ids.add(id)
                } else {
                    this.ids.delete(id)
                }
                this.notify()
                console.error('Failed to sync favorite:', e)
            }
        } else {
            this.saveAnonIds()
        }
    }

    // Directus API
    async addRemote(listingId) {
        const user = await auth.getUser()
        if (!user) return
        await directus.post('/items/favorites', {
            user: user.id,
            listing: listingId
        })
    }

    async removeRemote(listingId) {
        const user = await auth.getUser()
        if (!user) return
        const response = await directus.get('/items/favorites', {
            filter: {
                user: { _eq: user.id },
                listing: { _eq: listingId }
            },
            fields: ['id'],
            limit: 1
        })
        const item = response.data?.[0]
        if (item) {
            await directus.delete(`/items/favorites/${item.id}`)
        }
    }

    async fetchRemote() {
        const user = await auth.getUser()
        if (!user) return []
        const response = await directus.get('/items/favorites', {
            filter: {
                user: { _eq: user.id }
            },
            fields: ['listing'],
            limit: 200
        })
        return (response.data || []).map(f => f.listing).filter(Boolean)
    }

    async mergeOnLogin() {
        this.syncing = true
        try {
            const remoteIds = await this.fetchRemote()
            const localIds = this.getAnonIds()

            // Union merge
            const merged = new Set([...remoteIds, ...localIds])
            this.ids = merged

            // Push local-only favorites to server
            const remoteSet = new Set(remoteIds)
            const toAdd = localIds.filter(id => !remoteSet.has(id))
            for (const id of toAdd) {
                try {
                    await this.addRemote(id)
                } catch (e) {
                    console.error('Failed to sync favorite to server:', e)
                }
            }

            localStorage.removeItem(ANON_KEY)
            this.loaded = true
            this.notify()
        } catch (e) {
            console.error('Failed to merge favorites:', e)
            this.loaded = true
        }
        this.syncing = false
    }
}

export const favoritesService = new FavoritesService()
export default favoritesService
