import { ref, type Ref } from 'vue'
import axios, { AxiosError } from 'axios'
import { usePage } from '@inertiajs/vue3'
import type { SharedProps } from '@/Types/types'

export type SettingValue = string | number | boolean | null | Record<string, unknown> | unknown[]

export interface UpdateSettingOptions {
    endpoint?: (name: string) => string
    method?: 'patch' | 'put' | 'post'
}

export interface UpdateSettingResponse<T = unknown> {
    [key: string]: T
}

export interface UseUpdateSettingReturn {
    updateSetting: <T = SettingValue>(name: string, value: T) => Promise<UpdateSettingResponse>
    isUpdating: Ref<boolean>
    error: Ref<string | null>
}

interface LaravelValidationErrorResponse {
    message?: string
    errors?: Record<string, string[]>
}

export function useUpdateSetting(options: UpdateSettingOptions = {}): UseUpdateSettingReturn {
    const {
        endpoint = (name: string) => `/settings/${name}`,
        method = 'patch',
    } = options

    const isUpdating = ref(false)
    const error = ref<string | null>(null)

    async function updateSetting<T = SettingValue>(
        name: string,
        value: T
    ): Promise<UpdateSettingResponse> {
        isUpdating.value = true
        error.value = null

        const page = usePage<SharedProps>()
        if (!page.props.auth?.user) {
            error.value = 'You must be logged in to update settings.'
            return Promise.reject(new Error(error.value))
        }

        try {
            const response = await axios.request<UpdateSettingResponse>({
                method,
                url: endpoint(name),
                data: { value },
            })

            return response.data
        } catch (err) {
            const axiosError = err as AxiosError<LaravelValidationErrorResponse>

            if (axiosError.response?.status === 401) {
                error.value = 'You must be logged in to update settings.'
            } else if (axiosError.response?.status === 422) {
                error.value = axiosError.response.data?.message ?? 'Invalid setting value.'
            } else {
                error.value = 'Something went wrong updating your setting.'
            }

            throw err
        } finally {
            isUpdating.value = false
        }
    }

    return {
        updateSetting,
        isUpdating,
        error,
    }
}
