<template>
  <PageHeader>
    <template #center>
      <div
        class="ivyforms-header__navigation ivyforms-flex ivyforms-align-items-center ivyforms-justify-content-center ivyforms-gap-8"
      >
        <IvyButtonAction
          icon-only
          icon-start="chevron-left"
          icon-start-category="arrows"
          icon-start-type="outline"
          priority="tertiary"
          type="fill"
          size="s"
          :disabled="currentEntryIndex <= 1"
          @click="navigateToPreviousEntry"
        />
        <IvyButtonAction
          icon-only
          icon-start="chevron-right"
          icon-start-category="arrows"
          icon-start-type="outline"
          priority="tertiary"
          type="fill"
          size="s"
          :disabled="currentEntryIndex >= totalEntries"
          @click="navigateToNextEntry"
        />
        <span
          class="ivyforms-header__navigation-text ivyforms-flex ivyforms-align-items-center ivyforms-justify-content-center regular-14"
        >
          <template v-if="loading">
            <div class="ivyforms-count-loader"></div>
          </template>
          <template v-else>
            {{ currentEntryIndex }}/{{ totalEntries }} {{ getLabel('entries') }}
          </template>
        </span>
      </div>
    </template>
  </PageHeader>

  <div class="ivyforms-entry-page ivyforms-flex ivyforms-gap-8 ivyforms-p-8">
    <EntryPageSection />
    <EntryDetailsPagePanel />
    <IvyContextMenu />
    <IvyShortDialog show-close align-center type="error" width="342px" />
  </div>
</template>

<script setup lang="ts">
import { ref, computed, onMounted, onUnmounted, provide } from 'vue'
import { useRoute, useRouter, onBeforeRouteLeave, onBeforeRouteUpdate } from 'vue-router'
import { useEntry } from '@/stores/useEntry.ts'
import { useFormBuilder } from '@/stores/useFormBuilder.ts'
import { useAllEntries } from '@/stores/useAllEntries.ts'
import { useLabels } from '@/composables/useLabels.ts'
import { IVYFORMS_RESULTS_ENTRY_DETAILS, IVYFORMS_ENTRY_DETAILS } from '@/constants/pages.ts'
import { useWcagColors } from '@/composables/useWcagColors'
import IvyMessage from '@/views/_components/message/ivyMessage'
import { useEntryEditHolder } from '@/composables/entryEditBridge.ts'

type EntryPageEditIntegration = NonNullable<
  ReturnType<NonNullable<typeof window.IvyForms.setupEntryPageEditIntegration>>
>

type LiteNavigation = {
  navigateToPreviousEntry: () => Promise<void>
  navigateToNextEntry: () => Promise<void>
}

const { getLabel } = useLabels()
const { startWatching } = useWcagColors()
startWatching()
const route = useRoute()
const router = useRouter()
const entryStore = useEntry()
const formBuilderStore = useFormBuilder()
const allEntriesStore = useAllEntries()
const isResultsEntryRoute = computed(() => {
  return Boolean(route.path.includes('/results/entries') && route.params.formId)
})

const entryId = computed(() => {
  return isResultsEntryRoute.value ? route.params.entryId : route.params.id
})
const formId = computed(() => {
  return isResultsEntryRoute.value
    ? route.params.formId
    : entryStore.entry?.formId || formBuilderStore.formId
})
const entry = ref(null)
const entriesWithSameFormId = ref([])
const currentEntryIndex = ref(1)
const totalEntries = computed(() => entriesWithSameFormId.value.length)
const loading = ref(false)
const formName = computed(() => {
  return formBuilderStore.name ? formBuilderStore.name : ''
})

const entryEdit = useEntryEditHolder()
provide('entryEdit', entryEdit)

let editIntegration: EntryPageEditIntegration | null = null
let liteNavigation: LiteNavigation | null = null

const initEditIntegration = () => {
  const setup = window.IvyForms?.setupEntryPageEditIntegration
  if (!setup) {
    return
  }

  try {
    editIntegration = setup({
      entryEdit,
      route,
      router,
      entryId,
      formId,
      isResultsEntryRoute,
      getLabel,
      entryStore,
      entry,
      entriesWithSameFormId,
      currentEntryIndex,
      loading,
      formBuilderStore,
    })

    window.IvyForms!.startEntryEdit = editIntegration.startEntryEdit
  } catch (error) {
    console.error('Failed to initialize entry edit integration:', error)
    editIntegration = null
  }
}

initEditIntegration()
window.addEventListener('ivyforms:entry_edit_ready', initEditIntegration, { once: true })

const getLiteNavigation = (): LiteNavigation => {
  if (liteNavigation) {
    return liteNavigation
  }

  const getViewRouteName = () =>
    isResultsEntryRoute.value ? IVYFORMS_RESULTS_ENTRY_DETAILS : IVYFORMS_ENTRY_DETAILS

  liteNavigation = {
    navigateToPreviousEntry: async () => {
      if (currentEntryIndex.value <= 1) {
        return
      }
      currentEntryIndex.value--
      const previousEntryId = entriesWithSameFormId.value[currentEntryIndex.value - 1].id
      await router.push({
        name: getViewRouteName(),
        params: isResultsEntryRoute.value
          ? { formId: formId.value, entryId: previousEntryId }
          : { id: previousEntryId },
        query: route.query,
      })
      loading.value = true
      try {
        await entryStore.fetchEntry(Number(previousEntryId))
        entry.value = entryStore.entry
        currentEntryIndex.value =
          entriesWithSameFormId.value.findIndex(
            (row) => Number(row.id) === Number(previousEntryId),
          ) + 1
      } finally {
        loading.value = false
      }
    },
    navigateToNextEntry: async () => {
      if (currentEntryIndex.value >= entriesWithSameFormId.value.length) {
        return
      }
      currentEntryIndex.value++
      const nextEntryId = entriesWithSameFormId.value[currentEntryIndex.value - 1].id
      await router.push({
        name: getViewRouteName(),
        params: isResultsEntryRoute.value
          ? { formId: formId.value, entryId: nextEntryId }
          : { id: nextEntryId },
        query: route.query,
      })
      loading.value = true
      try {
        await entryStore.fetchEntry(Number(nextEntryId))
        entry.value = entryStore.entry
        currentEntryIndex.value =
          entriesWithSameFormId.value.findIndex((row) => Number(row.id) === Number(nextEntryId)) + 1
      } finally {
        loading.value = false
      }
    },
  }

  return liteNavigation
}

const navigateToPreviousEntry = async () => {
  if (editIntegration) {
    await editIntegration.navigateToPreviousEntry()
    return
  }
  await getLiteNavigation().navigateToPreviousEntry()
}

const navigateToNextEntry = async () => {
  if (editIntegration) {
    await editIntegration.navigateToNextEntry()
    return
  }
  await getLiteNavigation().navigateToNextEntry()
}

// Append a newly created entry to the local navigation list without refetching all entries.
const appendCreatedEntry = async (newEntryId: number) => {
  const formIdVal = entry.value?.formId
  if (formIdVal === null || formIdVal === undefined) {
    return
  }

  await allEntriesStore.fetchData({
    formId: formIdVal,
    page: 1,
    perPage: 1,
    shouldGetCount: true,
  })

  const exists = entriesWithSameFormId.value.some((item) => Number(item.id) === newEntryId)
  if (!exists) {
    entriesWithSameFormId.value = [
      ...entriesWithSameFormId.value,
      { id: newEntryId, formId: formIdVal },
    ].sort((a, b) => Number(a.id) - Number(b.id))
  }
}

const updateEntryData = async (newEntryId: number) => {
  loading.value = true
  try {
    await entryStore.fetchEntry(newEntryId)
    entry.value = entryStore.entry
    currentEntryIndex.value =
      entriesWithSameFormId.value.findIndex((row) => Number(row.id) === Number(newEntryId)) + 1
  } finally {
    loading.value = false
  }
}

// Called after an entry is created (add or duplicate): refresh the count and
// open the newly created entry in the details view.
const handleEntryCreated = async (newEntryId: number) => {
  // A count-refresh failure should not block opening the newly created entry.
  try {
    await appendCreatedEntry(newEntryId)
  } catch (error) {
    console.error('Failed to refresh entries count after create:', error)
  }

  try {
    if (isResultsEntryRoute.value) {
      await router.push({
        name: IVYFORMS_RESULTS_ENTRY_DETAILS,
        params: { formId: formId.value, entryId: newEntryId },
      })
    } else {
      await router.push({ name: IVYFORMS_ENTRY_DETAILS, params: { id: newEntryId } })
    }
    await updateEntryData(newEntryId)
  } catch (error) {
    console.error('Failed to open the newly created entry:', error)
    IvyMessage({
      message: getLabel('failed_to_get_entry'),
      type: 'error',
    })
  }
}

onMounted(async () => {
  loading.value = true
  try {
    await entryStore.fetchEntry(Number(entryId.value))
    entry.value = entryStore.entry
    if (isResultsEntryRoute.value && formId.value) {
      try {
        formBuilderStore.loadedForEntry = true
      } catch {
        // ignore if flag not available
      }
      await formBuilderStore.loadForm(Array.isArray(formId.value) ? formId.value[0] : formId.value)
    } else if (entry.value?.formId) {
      try {
        formBuilderStore.loadedForEntry = true
      } finally {
        await formBuilderStore.loadForm(entry.value.formId)
      }
    }
    const meta = allEntriesStore.paginationMeta as { page: number; perPage: number; total: number }
    const formIdVal = entry.value?.formId
    await allEntriesStore.fetchData({ formId: formIdVal, perPage: meta.total })
    entriesWithSameFormId.value = allEntriesStore.tableData
      .filter((entry) => Number(entry.formId) === Number(formIdVal))
      .sort((a, b) => Number(a.id) - Number(b.id))
    currentEntryIndex.value =
      entriesWithSameFormId.value.findIndex((entry) => Number(entry.id) === Number(entryId.value)) +
      1

    editIntegration?.registerEntryIdWatch()
  } catch (error) {
    console.error(getLabel('failed_to_get_entry'), error)
  } finally {
    loading.value = false
    await editIntegration?.syncAfterLoad()
  }
})

onBeforeRouteLeave((_to, _from, next) => {
  if (editIntegration) {
    editIntegration.onRouteLeave(next)
    return
  }
  try {
    formBuilderStore.formId = null
    formBuilderStore.loadedForEntry = false
  } finally {
    next()
  }
})

onBeforeRouteUpdate((to, from, next) => {
  if (editIntegration) {
    editIntegration.onRouteUpdate(to, from, next)
    return
  }
  next()
})

onUnmounted(() => {
  window.removeEventListener('ivyforms:entry_edit_ready', initEditIntegration)
  if (window.IvyForms?.startEntryEdit === editIntegration?.startEntryEdit) {
    delete window.IvyForms.startEntryEdit
  }
  if (editIntegration) {
    editIntegration.onUnmount()
    return
  }
  try {
    formBuilderStore.formId = null
    formBuilderStore.loadedForEntry = false
  } catch {
    // ignore if store is unavailable
  }
})

provide('entry', entry)

// Let the details panel refresh the count and open a newly created entry.
provide('onEntryCreated', handleEntryCreated)

provide('pageTitle', formName)
</script>

<style scoped lang="scss">
.ivyforms-entry-page {
  height: calc(100vh - 116px);
  overflow: hidden;
  display: flex;
  transition: height 0.3s ease-in-out;
}

.ivyforms-header {
  :deep(.ivyforms-header__left) {
    gap: 16px !important;
  }

  &__navigation {
    width: 200px;
    min-width: 200px;
    max-width: 200px;

    &-text {
      color: var(--map-base-text-0);
      width: 90px;
      max-width: 90px;
      text-align: center;
    }

    .ivyforms-count-loader {
      display: inline-block;
      width: 14px;
      height: 14px;
      border: 2px solid var(--map-base-brand-fill-0);
      border-top: 2px solid transparent;
      border-radius: 50%;
      animation: ivyforms-spin 1.2s linear infinite;
      vertical-align: middle;
    }
  }
}

@keyframes ivyforms-spin {
  to {
    transform: rotate(360deg);
  }
}
</style>
