import { Announcement } from '../api/announcement/types'
import { isCategory } from '../assets/category'
import { fallbackToUndefined, isBoolean, isInt } from './types'

const filterNames = ['userId', 'category', 'metro', 'obsolete'] as const
type FilterNames = typeof filterNames[number]

type FiltersType = Partial<
    Pick<Announcement, FilterNames & keyof Announcement> &
    {
        obsolete: boolean,
    }
>

const defaultFilters: FiltersType = { userId: undefined, category: undefined, metro: undefined, obsolete: false }

const URLEncodeFilters = (filters: FiltersType) => (
    Object.fromEntries(
        filterNames.map(
            fName => {
                const v = filters[fName]
                if (v || v === false) {
                    return [fName, v.toString()]
                }
                return [fName, undefined]
            }
        ).filter((p): p is [string, string] => typeof p[1] !== 'undefined')
    )
)

const URLDecoreFilters = (params: URLSearchParams): FiltersType => {
    const strFilters = Object.fromEntries(
        filterNames.map(
            fName => [fName, params.get(fName)]
        ).filter((p): p is [FilterNames, string] => p[1] !== null)
    ) as Record<FilterNames, string>

    return {
        userId: fallbackToUndefined(Number.parseInt(strFilters['userId']), isInt),
        category: fallbackToUndefined(strFilters['category'], isCategory),
        metro: strFilters['metro'],
        obsolete: fallbackToUndefined(strFilters['obsolete'] === 'true', isBoolean),
    }
}

const excludeFilters = <T extends FiltersType>(obj: T) => (
    filterNames.reduce((cObj, fName) => {
        delete cObj[fName]
        return cObj
    }, obj)
)

const convertFilterNames = (input: Record<string, string>) => ({
    ...input,
    ...(input['userId'] === undefined ? {} : { 'user_id': input['userId'] }),
})

export type { FilterNames, FiltersType }
export { defaultFilters, filterNames, URLEncodeFilters, URLDecoreFilters, excludeFilters, convertFilterNames }
