import { apiGet, isApiError, apiPost, apiPut } from '@/lib/api'

import type { Material,
	      MaterialIndexResponse,
	      MaterialVersion,
	      FetchMaterialsParams,
	      MaterialFilter,
	      MaterialSyncSuppression,
	      MaterialSidebarTag,
	      MaterialTagTree } from '@/types'

export type FetchMaterialTreeParams = {
    parentId?:       number | null
    materialFilter:  MaterialFilter }

export type MaterialSyncSuppressionResponse = { suppressions: MaterialSyncSuppression[] }

export type MaterialChangesResponse = {
    versions: MaterialVersion[]
    count:    number }

const MATERIAL_FILTERS: MaterialFilter[] = ['present', 'missing', 'any']


export const parseMaterialFilter = (
    value: unknown,
    fallback: MaterialFilter = 'present',
): MaterialFilter =>
    typeof value === 'string' && MATERIAL_FILTERS.includes (value as MaterialFilter)
    ? value as MaterialFilter
    : fallback


export const fetchMaterials = async (
    { q, tagState, mediaKind, createdFrom, createdTo,
      updatedFrom, updatedTo, sort, direction, page,
      tagId, includeDescendants, groupBy,
      limit }: FetchMaterialsParams,
): Promise<MaterialIndexResponse> =>
    await apiGet ('/materials', { params: {
	...(q && { q }),
	tag_state:   tagState,
	media_kind:  mediaKind,
	...(tagId != null && { tag_id: tagId }),
	...(includeDescendants && { include_descendants: '1' }),
	...(groupBy !== 'none' && { group_by: groupBy }),
	...(createdFrom && { created_from: createdFrom }),
	...(createdTo && { created_to: createdTo }),
	...(updatedFrom && { updated_from: updatedFrom }),
	...(updatedTo && { updated_to: updatedTo }),
	sort,
	direction,
	page,
	limit} })


export const fetchMaterial = async (id: string): Promise<Material | null> => {
  try
  {
    return await apiGet (`/materials/${ id }`)
  }
  catch (error)
  {
    if (isApiError (error) && error.response?.status === 404)
      return null
    throw error
  }
}


export const fetchMaterialChanges = async (
    { materialId, tag, eventType, page, limit }: {
	materialId?: string
	tag?:        string
	eventType?:  string
	page:        number
	limit:       number
    }): Promise<MaterialChangesResponse> =>
    await apiGet ('/materials/versions', { params: {
	...(materialId && { material_id: materialId }),
	...(tag && { tag }),
	...(eventType && { event_type: eventType }),
	page,
	limit} })


export const fetchMaterialTagTree = async (
    { parentId, materialFilter }: FetchMaterialTreeParams): Promise<MaterialSidebarTag[]> =>
    await apiGet ('/tags/with-depth', { params: {
	...(parentId != null && { parent: String (parentId) }),
	material_filter: materialFilter} })


export const fetchMaterialTagByName = async (
    name: string,
    materialFilter: MaterialFilter): Promise<MaterialTagTree | null> => {
  try
  {
    return await apiGet (`/tags/name/${ encodeURIComponent (name) }/materials`,
			 { params: { material_filter: materialFilter } })
  }
  catch (error)
  {
    if (isApiError (error) && error.response?.status === 404)
      return null
    throw error
  }
}


export const createMaterial = async (formData: FormData): Promise<Material> =>
    await apiPost ('/materials', formData)


export const updateMaterial = async (
    id: string,
    formData: FormData): Promise<Material> =>
    await apiPut (`/materials/${ id }`, formData)


export const fetchMaterialSyncSuppressions =
    async (): Promise<MaterialSyncSuppressionResponse> =>
        await apiGet ('/materials/suppressions')


export const createMaterialSyncSuppression = async (
    payload: {
        sourceKind:   string
        sourceUri?:   string
        drivePath?:   string
        driveFileId?: string
        reason:       string
    }): Promise<MaterialSyncSuppression> =>
    await apiPost ('/materials/suppressions', {
        source_kind:   payload.sourceKind,
        source_uri:    payload.sourceUri,
        drive_path:    payload.drivePath,
        drive_file_id: payload.driveFileId,
        reason:        payload.reason})
