import { inject, ref } from 'vue'

// Base composable to access the Strapi client
const getStrapiClient = () => {
    const client = inject('strapi')
    if (!client)
        throw new Error(
            'Strapi client not initialized. Did you install the plugin?',
        )
    return client
}

// Merge default and user options
const mergeOptions = (userOptions = {}) => {
    return { pLevel: '5', ...userOptions }
}

// Singleton instance for global data
let globalInstance = null

/**
 * Use the global singleton data with caching
 * This composable ensures the global data is only fetched once,
 * even when called from multiple places
 * @param {object} options - optional query options
 */
export const useStrapiGlobal = async (options = {}) => {
    // Return existing instance if already fetched
    if (globalInstance) {
        return globalInstance
    }

    // Create new instance
    const data = ref(null)
    const loading = ref(true)
    const error = ref(null)
    const client = getStrapiClient()

    // Store the instance before making the request
    globalInstance = { data, loading, error }

    try {
        const response = await client
            .single('global')
            .find(mergeOptions(options))
        data.value = response.data
    } catch (err) {
        error.value = err
        console.error(err)
        // Reset instance on error so it can be retried
        globalInstance = null
    } finally {
        loading.value = false
    }

    return globalInstance
}

/**
 * Reset the global singleton cache
 * Useful for forcing a refetch of global data
 */
export const resetStrapiGlobal = () => {
    globalInstance = null
}

/**
 * Use a singleton content type
 * @param {string} uid - Strapi singleton UID
 * @param {object} options - optional query options
 */
export const useStrapiSingle = async (uid, options = {}) => {
    const data = ref(null)
    const loading = ref(true)
    const error = ref(null)
    const client = getStrapiClient()

    try {
        const response = await client.single(uid).find(mergeOptions(options))
        data.value = response.data
    } catch (err) {
        error.value = err
        console.error(err)
    } finally {
        loading.value = false
    }

    return { data, loading, error }
}

/**
 * Use a single entry by ID
 * @param {string} contentType
 * @param {number|string} id
 * @param {object} options - optional query options
 */
export const useStrapiOne = async (contentType, id, options = {}) => {
    const data = ref(null)
    const loading = ref(true)
    const error = ref(null)
    const client = getStrapiClient()

    try {
        const response = await client
            .entity(contentType)
            .findOne({ id, ...mergeOptions(options) })
        data.value = response.data
    } catch (err) {
        error.value = err
        console.error(err)
    } finally {
        loading.value = false
    }

    return { data, loading, error }
}

/**
 * Use a collection of entries
 * @param {string} contentType
 * @param {object} options - optional query options
 */
export const useStrapiMany = async (contentType, options = {}) => {
    const data = ref(null)
    const loading = ref(true)
    const error = ref(null)
    const client = getStrapiClient()

    try {
        const response = await client
            .entity(contentType)
            .find(mergeOptions(options))
        data.value = response.data
    } catch (err) {
        error.value = err
        console.error(err)
    } finally {
        loading.value = false
    }

    return { data, loading, error }
}
