import { useEffect, useRef, useState } from 'react'

import { API_URL } from '../../config'
import { isLiteralUnion } from '../../utils/types'
import { handleHTTPErrors } from '../../utils'

const addErrors = ['Не удалось опубликовать объявление', 'Неверный ответ от сервера', 'Неизвестная ошибка'] as const
type AddError = typeof addErrors[number]

const isAddError = (obj: unknown): obj is AddError => isLiteralUnion(obj, addErrors)

const buttonStates = ['Опубликовать', 'Загрузка...', 'Опубликовано', 'Отменено'] as const
type ButtonState = typeof buttonStates[number] | AddError

type AddResponse = {
    Answer: boolean
}

const isAddResponse = (obj: unknown): obj is AddResponse =>
    typeof obj === 'object' && obj !== null && typeof Reflect.get(obj, 'Answer') === 'boolean'


const useAddAnnouncement = () => {
    const [status, setStatus] = useState<ButtonState>('Опубликовать')

    const timerIdRef = useRef<number>()
    const abortControllerRef = useRef<AbortController>()

    const doAdd = async (formData: FormData) => {
        if (status === 'Загрузка...') {
            abortControllerRef.current?.abort()
            setStatus('Отменено')
            timerIdRef.current = setTimeout(() => setStatus('Опубликовать'), 3000)
            return
        }

        setStatus('Загрузка...')

        const abortController = new AbortController()
        abortControllerRef.current = abortController

        try {
            const res = await fetch(API_URL + '/announcement', {
                method: 'PUT',
                body: formData,
                signal: abortController.signal
            })

            handleHTTPErrors(res)

            const data: unknown = await res.json()

            if (!isAddResponse(data)) throw new Error('Неверный ответ от сервера')

            if (!data.Answer) {
                throw new Error('Не удалось опубликовать объявление')
            }
            setStatus('Опубликовано')

        } catch (err) {
            setStatus(isAddError(err) ? err : 'Неизвестная ошибка')
            timerIdRef.current = setTimeout(() => setStatus('Опубликовать'), 10000)
        }
    }

    useEffect(() => {
        const abortController = abortControllerRef.current
        return () => {
            clearTimeout(timerIdRef.current)
            abortController?.abort()
        }
    })

    return { doAdd, status }
}

export default useAddAnnouncement
