import { ref } from 'vue'

// Factory for CRUD handler state and actions
export function createCrudHandler<T = any>(crud: {
  post: (...args: any[]) => Promise<any>
  patch: (...args: any[]) => Promise<any>
  remove: (...args: any[]) => Promise<any>
}) {
  const recId = ref<number>(0)
  const recAction = ref<string>('')
  const recItem = ref<T | null>(null)
  const isReadonly = ref(false)
  const isProcessing = ref(false)
  const isFormEntryDialogOpen = ref(false)
  const isRecordConfirmationOpen = ref(false)

  function onResetState() {
    recId.value = 0
    recAction.value = ''
    recItem.value = null
  }

  async function handleActionSave(values: any, refresh: () => void, reset: () => void, toast: ToastFn) {
    isProcessing.value = true
    await handleAsyncAction<[any], any>({
      action: crud.post,
      args: [values],
      toast,
      successMessage: 'Data berhasil disimpan',
      errorMessage: 'Gagal menyimpan data',
      onSuccess: () => {
        isFormEntryDialogOpen.value = false
        if (refresh) refresh()
      },
      onFinally: (isSuccess: boolean) => {
        if (isSuccess) setTimeout(reset, 300)
        onResetState()
        isProcessing.value = false
      },
    })
  }

  async function handleActionEdit(
    id: number | string,
    values: any,
    refresh: () => void,
    reset: () => void,
    toast: ToastFn,
  ) {
    isProcessing.value = true
    await handleAsyncAction<[number | string, any], any>({
      action: crud.patch,
      args: [id, values],
      toast,
      successMessage: 'Data berhasil diubah',
      errorMessage: 'Gagal mengubah data',
      onSuccess: () => {
        isFormEntryDialogOpen.value = false
        if (refresh) refresh()
      },
      onFinally: (isSuccess: boolean) => {
        if (isSuccess) setTimeout(reset, 300)
        onResetState()
        isProcessing.value = false
      },
    })
  }

  async function handleActionRemove(id: number | string, refresh: () => void, toast: ToastFn) {
    isProcessing.value = true
    await handleAsyncAction<[number | string], any>({
      action: crud.remove,
      args: [id],
      toast,
      successMessage: 'Data berhasil dihapus',
      errorMessage: 'Gagal menghapus data',
      onSuccess: () => {
        isRecordConfirmationOpen.value = false
        if (refresh) refresh()
      },
      onFinally: () => {
        setTimeout(refresh, 300)
        onResetState()
        isProcessing.value = false
      },
    })
  }

  function handleCancelForm(reset: () => void) {
    isFormEntryDialogOpen.value = false
    isReadonly.value = false
    onResetState()
    setTimeout(reset, 300)
  }

  return {
    recId,
    recAction,
    recItem,
    isReadonly,
    isProcessing,
    isFormEntryDialogOpen,
    isRecordConfirmationOpen,
    onResetState,
    handleActionSave,
    handleActionEdit,
    handleActionRemove,
    handleCancelForm,
  }
}

// Factory for CRUD handler state and actions
export function genCrudHandler<T = any>(crud: {
  create: (...args: any[]) => Promise<any>
  update: (...args: any[]) => Promise<any>
  remove: (...args: any[]) => Promise<any>
}) {
  const recId = ref<number>(0)
  const recAction = ref<string>('')
  const recItem = ref<T | null>(null)
  const isReadonly = ref(false)
  const isProcessing = ref(false)
  const isFormEntryDialogOpen = ref(false)
  const isRecordConfirmationOpen = ref(false)

  function onResetState() {
    recId.value = 0
    recAction.value = ''
    recItem.value = null
  }

  async function handleActionSave(
    values: any,
    refresh: () => void,
    reset: () => void,
    toast: ToastFn,
  ): Promise<any | null> {
    isProcessing.value = true

    let successResponse: any = null

    await handleAsyncAction<[any], any>({
      action: crud.create,
      args: [values],
      toast,
      successMessage: 'Data berhasil disimpan',
      errorMessage: 'Gagal menyimpan data',
      onSuccess: (result) => {
        isFormEntryDialogOpen.value = false
        if (refresh) refresh()
        successResponse = result
      },
      onFinally: (isSuccess: boolean) => {
        if (isSuccess) setTimeout(reset, 500)
        isProcessing.value = false
      },
    })

    return successResponse
  }

  async function handleActionEdit(
    id: number | string,
    values: any,
    refresh: () => void,
    reset: () => void,
    toast: ToastFn,
  ) {
    isProcessing.value = true
    await handleAsyncAction<[number | string, any], any>({
      action: crud.update,
      args: [id, values],
      toast,
      successMessage: 'Data berhasil diubah',
      errorMessage: 'Gagal mengubah data',
      onSuccess: () => {
        isFormEntryDialogOpen.value = false
        if (refresh) refresh()
      },
      onFinally: (isSuccess: boolean) => {
        if (isSuccess) setTimeout(reset, 500)
        isProcessing.value = false
      },
    })
  }

  async function handleActionRemove(id: number | string, refresh: () => void, toast: ToastFn) {
    isProcessing.value = true
    await handleAsyncAction<[number | string], any>({
      action: crud.remove,
      args: [id],
      toast,
      successMessage: 'Data berhasil dihapus',
      errorMessage: 'Gagal menghapus data',
      onSuccess: () => {
        isRecordConfirmationOpen.value = false
        if (refresh) refresh()
      },
      onFinally: () => {
        setTimeout(refresh, 300)
        onResetState()
        isProcessing.value = false
      },
    })
  }

  function handleCancelForm(reset: () => void) {
    isFormEntryDialogOpen.value = false
    isReadonly.value = false
    onResetState()
    setTimeout(reset, 300)
  }

  return {
    recId,
    recAction,
    recItem,
    isReadonly,
    isProcessing,
    isFormEntryDialogOpen,
    isRecordConfirmationOpen,
    onResetState,
    handleActionSave,
    handleActionEdit,
    handleActionRemove,
    handleCancelForm,
  }
}

// Reusable async handler for CRUD actions with toast and state management
export type ToastFn = (params: { title: string; description: string; variant: 'default' | 'destructive' }) => void

export interface HandleAsyncActionOptions<T extends any[], R> {
  action: (...args: T) => Promise<R & { success: boolean }>
  args?: T
  toast: ToastFn
  successMessage: string
  errorMessage: string
  onSuccess?: (result: R) => void
  onError?: (error: unknown) => void
  onFinally?: (isSuccess: boolean) => void
}

export async function handleAsyncAction<T extends any[], R>({
  action,
  args = [] as unknown as T,
  toast,
  successMessage,
  errorMessage,
  onSuccess,
  onError,
  onFinally,
}: HandleAsyncActionOptions<T, R>) {
  let isSuccess = false
  try {
    const result = await action(...args)
    if (result.success) {
      toast({ title: 'Berhasil', description: successMessage, variant: 'default' })
      isSuccess = true
      if (onSuccess) onSuccess(result)
    } else {
      toast({ title: 'Gagal', description: errorMessage, variant: 'destructive' })
      if (onError) onError(result)
    }
  } catch (error) {
    toast({ title: 'Gagal', description: errorMessage, variant: 'destructive' })
    if (onError) onError(error)
  } finally {
    if (onFinally) onFinally(isSuccess)
  }
}
