import { createURLBuilder } from '@rokoli/bnb/common'

import { ID, PartialUpdateOperation } from '@rokoli/bnb/drf'
import { APIObject } from '@rokoli/bnb'
import { MaybeRefOrGetter, toValue } from 'vue'
import { areSetsEqual } from '@/util'

export const createTankURL = createURLBuilder(import.meta.env.VUE_APP_API_TANK, false)
export const createSteeringURL = createURLBuilder(import.meta.env.VUE_APP_API_STEERING)

export function createRelationManager<T extends APIObject>(
  partialUpdate: PartialUpdateOperation<T, Partial<T>>,
  getObject?: MaybeRefOrGetter<T>,
) {
  type AnyRelations = Partial<{ [K in keyof T]: T[K] extends ID[] ? T[K] : never }>

  return function (data: AnyRelations, object?: T): Promise<T> {
    const obj = typeof object !== 'undefined' ? object : toValue(getObject)
    const updateData = {} as Record<keyof T, ID[]>

    if (typeof obj === 'undefined') {
      throw new TypeError('You must either pass an object getter or pass the object on update.')
    }

    for (const _key of Object.keys(data)) {
      const key = _key as keyof T
      const currentValue = obj[key] as ID[]
      const newValue = data[key] as ID[]

      if (!Array.isArray(currentValue) || !Array.isArray(newValue)) {
        const message = `${_key} is not a relation on object`
        console.error(message, obj)
        throw new TypeError(message)
      }

      if (!areSetsEqual(currentValue, newValue)) {
        updateData[key] = newValue
      }
    }

    if (Object.keys(updateData).length > 0) {
      return partialUpdate(obj.id, updateData as Partial<T>)
    } else {
      return Promise.resolve(obj as T)
    }
  }
}