<script setup lang="ts">
import { ref, watch, onMounted, computed, nextTick, onBeforeUnmount } from 'vue'
import {
  useRouter,
  useRoute,
  onBeforeRouteLeave,
  onBeforeRouteUpdate,
  type RouteLocationRaw,
} from 'vue-router'
import { Loader2 } from 'lucide-vue-next'
import { toast } from 'vue-sonner'

import ConfigureAgent from './ConfigureAgent.vue'
import TestAgent from './TestAgent.vue'
import ShareAgent from './ShareAgent.vue'
import CustomMainHeader from '@/components/CustomMainHeader.vue'
import { Button } from '@/components/ui/button'
import {
  AlertDialog,
  AlertDialogContent,
  AlertDialogHeader,
  AlertDialogTitle,
  AlertDialogDescription,
  AlertDialogFooter,
  AlertDialogCancel,
  AlertDialogAction,
} from '@/components/ui/alert-dialog'
import { Tabs, TabsList, TabsTrigger, TabsContent } from '@/components/ui/tabs'
import { useSidebar } from '@/components/ui/sidebar'
import { Tooltip, TooltipContent, TooltipTrigger } from './ui/tooltip'

import { useAgentStore } from '@/store/agentStore'
import { useAgentCatalogStore } from '@/store/agentCatalogStore'
import { useSocket } from '@/composables/useSocket'
import { API } from '@/Api'
import { usePrefStore } from '@/store/prefStore'
import { WT1iser } from '@/lib/wt1'
import { isIndexing } from '@/constants/indexing'

/* ------------------------------------------------------------------ */
/* stores & reactive helpers                                          */
/* ------------------------------------------------------------------ */
const router = useRouter()
const route = useRoute()
const { isDesktop, openMobile } = useSidebar()

const agentStore = useAgentStore()
const catalogStore = useAgentCatalogStore()
const prefStore = usePrefStore()

const {
  draft,
  initDraft,
  loadDraft,
  autosave,
  flushPendingAutosave,
  publishAgent,
  refreshSnapshot,
  hasUnsavedChanges,
} = agentStore

const isSaving = ref(false)
const isPublishing = ref(false)
const showPublishDialog = ref(false)
const showDiscardDialog = ref(false)
const showShareDialog = ref(false)
const publishingStatus = ref<'idle' | 'publishing' | 'published' | 'failed'>('idle')
const isNewRoute = computed(() => route.name === 'NewAgent')
const socket = useSocket()
const showSuccessBanner = ref(false)

/* delete via sidebar */
function requestDeleteAgent() {
  if (!draft.id) return
  WT1iser.deleteAgent(draft.status ?? 'draft')
  window.dispatchEvent(
    new CustomEvent('request-delete-agent', { detail: { id: draft.id, name: draft.name } })
  )
}

/* ------------------------------------------------------------------ */
/* mount-gate for <TestAgent>                                         */
/* ------------------------------------------------------------------ */
const draftReady = ref(false)

async function prepareDraft() {
  flushPendingAutosave()
  draftReady.value = false
  publishingStatus.value = 'idle'
  isPublishing.value = false
  if (isNewRoute.value) {
    initDraft()
  } else if (route.params.id) {
    await loadDraft(route.params.id as string)
    // Check publishing status after loading draft
    await checkPublishingStatus()
  }

  draftReady.value = true
}

/* react to route changes – skip the first run */
watch(
  () => [route.name, route.params.id, route.query.new],
  //([newName,newId,newTok],[oldName]) => {
  ([oldName]) => {
    if (oldName === undefined) return // ignore initial tick
    prepareDraft().then(() => {
      /* focus the name input when we start a brand-new draft */
      if (isNewRoute.value)
        nextTick(() => {
          const inp = document.querySelector('input[name="agent-name"]') as HTMLInputElement | null
          inp?.focus()
        })
    })
  }
)

/* ------------------------------------------------------------------ */
/* derived helpers                                                    */
/* ------------------------------------------------------------------ */
const noProjectCreated = computed(() => agentStore.noProjectCreated)

// Check if this is truly a new agent (not an existing one being edited)
const isNewAgent = computed(() => !draft.published_version)

// Only enable publish if there are actual changes (for existing agents) or required fields are filled (for new agents)
const canPublish = computed(() => {
  // Basic validation
  if (noProjectCreated.value || draft.description.trim() === '') {
    return false
  }

  // Can't publish while publishing
  if (publishingStatus.value === 'publishing') {
    return false
  }

  // For new agents, just check required fields
  if (isNewAgent.value) {
    return true
  }

  // For existing agents, check if there are unsaved changes
  return hasUnsavedChanges()
})

const hasPublishedVersion = computed(() => !!draft.published_version)
const indexing = computed(() => draft.indexing)
const indexingBusy = computed(() => isIndexing(indexing.value?.status))
const changesSnapshot = ref({} as any)
/* propagate updates coming from <ConfigureAgent> */
function handleUpdateDraft(payload: any) {
  changesSnapshot.value = Object.assign(payload)
  // Reflect ONLY systemPrompt immediately to avoid debounce delay
  if (Object.prototype.hasOwnProperty.call(payload, 'systemPrompt')) {
    draft.systemPrompt = payload.systemPrompt || ''
  }
  // When the agent is not created yet but we have a non-empty system prompt, trigger creation now
  const hasNonEmptySystemPrompt =
    typeof payload.systemPrompt === 'string' && payload.systemPrompt.trim() !== ''
  if (hasNonEmptySystemPrompt || !noProjectCreated.value) {
    // Non-shallow autosave to create/update the agent
    autosave(payload, false)
  } else {
    // Otherwise, keep shallow autosave until agent exists
    autosave(payload, true)
  }
}
watch(
  () => draft.project_key,
  (newKey: string | undefined) => {
    if (newKey && noProjectCreated.value) {
      // Project was just created
      toast.success('Agent created successfully! You can now publish it.')
    }
  }
)
/* publish agent */
async function onPublish() {
  showPublishDialog.value = false
  isPublishing.value = true
  publishingStatus.value = 'publishing'
  WT1iser.publishAgent(draft.status ?? 'draft')
  try {
    await publishAgent()
    // Publishing started successfully - now wait for events
  } catch (e: any) {
    isPublishing.value = false
    publishingStatus.value = 'failed'
    toast.error(e.message || 'Failed to start publishing')
  }
}
/*  */
async function onDiscardChanges() {
  showDiscardDialog.value = false

  if (!draft.published_version) return

  try {
    const loadingToast = toast.loading('Discarding changes…')

    await catalogStore.updateAgent({ id: draft.id, hasUnpublishedChanges: false })

    // Single API call handles everything server-side
    await API.discardAgentChanges(draft.id)

    // Reload agent from server to get clean state
    await loadDraft(draft.id)

    toast.dismiss(loadingToast)
    toast.success('All changes discarded successfully')
  } catch (err: any) {
    toast.error(err?.response?.data?.error || 'Failed to discard changes')
  }
}

async function handleDiscardChanges() {
  // Reload agent from server to get clean state
  await loadDraft(draft.id)
}
async function handlePublishEvent(event: any) {
  const isCurrent = event.agent_id === draft.id

  if (event.event_type === 'publish_completed') {
    // First remove any draft
    catalogStore.agents = catalogStore.agents.filter(
      (a) => !(a.id === event.agent_id && a.status === 'draft')
    )

    catalogStore.updateAgent({
      id: event.agent_id,
      name: event.agent_name || draft.name,
      status: 'active',
      published_at: event.timestamp,
      published_version: true,
      hasUnpublishedChanges: false,
      exampleQuestions: draft.sample_questions,
    })
  }

  if (!isCurrent) {
    if (event.event_type === 'publish_completed') {
      toast.success('Agent published successfully!')
    } else if (event.event_type === 'publish_failed') {
      toast.error(event.error || 'Publishing failed')
    }
    return
  }

  switch (event.event_type) {
    case 'publish_started':
      publishingStatus.value = 'publishing'
      break

    case 'publish_completed':
      publishingStatus.value = 'published'
      isPublishing.value = false
      showSuccessBanner.value = true
      // Auto-hide success banner after 5 seconds
      setTimeout(() => {
        showSuccessBanner.value = false
      }, 5000)
      draft.published_at = event.timestamp
      draft.publishing_status = 'published'
      draft.status = 'active'

      /* Freeze current snapshot so autosave sees "no change"    */
      autosave.cancel?.()
      refreshSnapshot()

      // Update hasPublishedVersion for UI
      draft.published_version = {
        name: draft.name,
        description: draft.description,
        system_prompt: draft.systemPrompt,
        kb_description: draft.kbDescription,
        tools: draft.tools,
        llmid: draft.llmid,
        embedding_llm_id: draft.embeddingLlmId,
        documents: draft.documents || [],
        sample_questions: draft.sample_questions,
      }
      draft.hasUnpublishedChanges = false
      break

    case 'publish_failed':
      publishingStatus.value = 'failed'
      isPublishing.value = false
      toast.error(event.error || 'Publishing failed')
      break
  }
}

async function checkPublishingStatus() {
  const agentId = draft.id || (route.params.id as string)
  if (!agentId) return

  try {
    const { data } = await API.getPublishingStatus(agentId)
    publishingStatus.value = data.publishing_status || 'idle'
    isPublishing.value = publishingStatus.value === 'publishing'

    if (publishingStatus.value === 'publishing' && !draft.id) {
      await loadDraft(agentId)
    }
  } catch (err) {
    console.error('Failed to check publishing status', err)
  }
}
let statusTimer: number | null = null

onMounted(() => {
  openMobile.value = false

  prepareDraft().then(() => {
    checkPublishingStatus()
  })

  if (socket.value) {
    socket.value.on('agent:publish_event', handlePublishEvent)
  }
  statusTimer = window.setInterval(async () => {
    if (publishingStatus.value === 'publishing') {
      await checkPublishingStatus()
    }
  }, 4000)
})

onBeforeUnmount(() => {
  if (socket.value) {
    socket.value.off('agent:publish_event', handlePublishEvent)
  }
  if (statusTimer) clearInterval(statusTimer)
})

const favoriteAgents = prefStore.favoriteAgents

async function toggleFavorite() {
  const isFavorite = favoriteAgents[draft.id] || false
  WT1iser.favoriteAgent(isFavorite)
  await prefStore.toggleFavoriteAgent(draft.id, !isFavorite)
}

const showDiscardDialogBeforeLeaving = ref(false)
const pendingRoute = ref<RouteLocationRaw | null>(null)

// TODO: With autocreate it will automatically create the agent even if the user leaves the page anyways
// Helper function to check if we should show the unsaved changes dialog
function shouldShowUnsavedDialog() {
  // const noFilledInfo =
  //   isEmpty(draft.name) &&
  //   isEmpty(draft.description) &&
  //   isEmpty(draft.systemPrompt) &&
  //   isEmpty(draft.sample_questions) &&
  //   isEmpty(draft.kbDescription)

  // return !draft.project_key && !noFilledInfo
  return false
}

// Called when user tries to navigate to a different route
onBeforeRouteLeave((to, _, next) => {
  if (shouldShowUnsavedDialog()) {
    showDiscardDialogBeforeLeaving.value = true
    pendingRoute.value = to
    next(false) // cancel for now
  } else {
    next(true) // allow navigation
  }
})

// Called when user tries to navigate to the same route with different params/query
onBeforeRouteUpdate((to, _, next) => {
  if (shouldShowUnsavedDialog()) {
    showDiscardDialogBeforeLeaving.value = true
    pendingRoute.value = to
    next(false) // cancel for now
  } else {
    next(true) // allow navigation
  }
})

function confirmLeave() {
  showDiscardDialogBeforeLeaving.value = false
  agentStore.initDraft() // reset draft
  if (pendingRoute.value) {
    router.push(pendingRoute.value) // retry navigation
    pendingRoute.value = null
  }
}

function cancelLeave() {
  showDiscardDialogBeforeLeaving.value = false
  pendingRoute.value = null
}
</script>

<template>
  <div class="relative flex flex-1 flex-col overflow-hidden">
    <!-- Fixed header with back button and actions integrated -->
    <header
      class="flex items-center justify-between w-full h-[57px] py-1.5 border-t-[4px] border-t-primary border-b border-b-border"
    >
      <!-- Left side: Header component + Back button -->
      <div class="flex items-center">
        <CustomMainHeader :sidebarOpen="true" />
      </div>
      <!-- Right side: Action buttons -->
      <!-- Desktop action buttons -->
      <div v-if="isDesktop" class="flex items-center space-x-2 py-1.5 pr-3">
        <!-- Add/Remove Favorite button -->
        <Tooltip v-if="hasPublishedVersion" :key="`fav-${draft.id}`">
          <TooltipTrigger as-child>
            <span class="inline-flex">
              <Button
                variant="outline"
                size="lg"
                class="px-4"
                @click="toggleFavorite"
                :disabled="isPublishing"
              >
                <template v-if="favoriteAgents[draft.id]">
                  <i class="dku-icon-star-fill-16 text-[#F9BD38]" />
                </template>
                <template v-else>
                  <i class="dku-icon-star-outline-16 text-card-foreground" />
                </template>
              </Button>
            </span>
          </TooltipTrigger>
          <TooltipContent hide-arrow>
            <p>{{ favoriteAgents[draft.id] ? 'Remove from Favorites' : 'Add to Favorites' }}</p>
          </TooltipContent>
        </Tooltip>
        <!-- Delete button -->
        <Button
          v-if="!agentStore.noProjectCreated"
          variant="outline"
          size="lg"
          class="px-4"
          :disabled="!draft.id || isPublishing"
          @click="requestDeleteAgent"
        >
          <i class="dku-icon-trash-16" />
          Delete
        </Button>

        <!-- Share button (only if published) -->
        <Button
          v-if="hasPublishedVersion"
          variant="outline"
          size="lg"
          class="px-4"
          @click="showShareDialog = true"
          :disabled="isPublishing"
        >
          <i class="dku-icon-share-16" />
          Share
        </Button>

        <!-- Publish button -->
        <Tooltip :key="`pub-${draft.id}`">
          <TooltipTrigger as-child>
            <span class="inline-flex">
              <Button
                @click="showPublishDialog = true"
                :disabled="!canPublish || isPublishing || indexingBusy"
                size="lg"
                class="px-4"
              >
                <template v-if="isPublishing">
                  <Loader2 class="w-4 h-4 animate-spin mr-2" />Publishing…
                </template>
                <template v-else>
                  <i class="dku-icon-publish-16 w-4 h-4 mr-1" />
                  {{ isNewAgent ? 'Publish' : 'Publish Changes' }}
                </template>
              </Button>
            </span>
          </TooltipTrigger>
          <TooltipContent hide-arrow v-if="!canPublish">
            {{
              publishingStatus == 'published' && !hasUnsavedChanges()
                ? 'No new changes to publish'
                : ' To publish, please fill in all required fields'
            }}
          </TooltipContent>
          <TooltipContent hide-arrow v-else-if="indexingBusy">
            Documents are being processed. Please wait until processing is complete to publish.
          </TooltipContent>
        </Tooltip>
      </div>

      <!-- Mobile action buttons -->
      <div v-else class="flex items-center space-x-1 py-2 pr-3">
        <!-- Favorite button -->
        <Tooltip>
          <TooltipTrigger as-child>
            <Button
              v-if="hasPublishedVersion"
              size="lg"
              class="px-4"
              variant="outline"
              @click="toggleFavorite"
              :disabled="isPublishing"
            >
              <template v-if="favoriteAgents[draft.id]">
                <i class="dku-icon-star-fill-16 text-[#F9BD38]" />
              </template>
              <template v-else>
                <i class="dku-icon-star-outline-16 text-card-foreground" />
              </template>
            </Button>
          </TooltipTrigger>
          <TooltipContent>
            <p>
              {{ favoriteAgents[draft.id] ? 'Remove from Favorites' : 'Add to Favorites' }}
            </p>
          </TooltipContent>
        </Tooltip>
        <!-- Delete button (mobile) -->
        <Button
          v-if="!agentStore.noProjectCreated"
          variant="outline"
          size="lg"
          class="px-4"
          :disabled="isPublishing"
          @click="requestDeleteAgent"
        >
          <i class="dku-icon-trash-16" />
          <span class="sr-only">Delete agent</span>
        </Button>

        <!-- Share button (only if published) -->
        <Button
          v-if="hasPublishedVersion && !isNewRoute"
          variant="outline"
          size="lg"
          class="px-4"
          @click="showShareDialog = true"
          :disabled="isPublishing"
        >
          <i class="dku-icon-share-16" />
        </Button>
        <!-- Publish button -->
        <Button
          v-if="!noProjectCreated"
          @click="showPublishDialog = true"
          :disabled="!canPublish || isPublishing"
          size="lg"
          class="px-4"
        >
          <template v-if="isPublishing">
            <Loader2 class="w-4 h-4 animate-spin" />
          </template>
          <template v-else>
            <i class="dku-icon-publish-16 w-4 h-4" />
            Publish
          </template>
          <span class="sr-only">{{ isNewAgent ? 'Publish' : 'Publish Changes' }}</span>
        </Button>
      </div>
    </header>

    <div class="flex-1 flex flex-col overflow-hidden p-3 pb-0">
      <!-- desktop -->
      <div v-if="isDesktop" class="flex flex-1 gap-4 min-h-0">
        <div class="flex-1 overflow-auto">
          <ConfigureAgent
            v-if="draftReady"
            :key="draft.id"
            :draft="draft"
            :isPublishing="isPublishing"
            @updateDraft="handleUpdateDraft"
            @discardChanges="handleDiscardChanges"
          />
        </div>
        <div class="flex-1 min-h-0 border border-border mb-5 pt-2 pb-1" style="border-radius: 12px">
          <TestAgent
            v-if="draftReady"
            :key="draft.id"
            :chatDisabled="noProjectCreated"
            :skipInitialLoad="isNewRoute"
            class="px-3"
          />
        </div>
      </div>

      <div v-else class="flex-1 flex flex-col min-h-0">
        <Tabs
          defaultValue="configure"
          :unmountOnHide="false"
          class="flex flex-col flex-1 min-h-0 w-full"
        >
          <TabsList class="flex border-b mb-4 w-full">
            <TabsTrigger value="configure" class="flex-1">Create</TabsTrigger>
            <TabsTrigger value="test" class="flex-1">Test</TabsTrigger>
          </TabsList>

          <TabsContent value="configure" class="flex-1 overflow-auto">
            <ConfigureAgent
              v-if="draftReady"
              :draft="draft"
              :isPublishing="isPublishing"
              @updateDraft="handleUpdateDraft"
              @discardChanges="handleDiscardChanges"
              :key="draft.id"
            />
          </TabsContent>

          <TabsContent value="test" class="flex-1 min-h-0 pb-3 mb-5">
            <div class="border border-border pt-2 px-3 pb-1" style="border-radius: 12px">
              <TestAgent
                :key="draft.id"
                :chatDisabled="noProjectCreated"
                :skipInitialLoad="isNewRoute"
              />
            </div>
          </TabsContent>
        </Tabs>
      </div>
    </div>

    <div v-if="isSaving" class="absolute inset-0 bg-white/75 flex items-center justify-center">
      <Loader2 class="w-12 h-12 animate-spin" />
    </div>

    <!-- Publish confirmation dialog -->
    <AlertDialog v-model:open="showPublishDialog">
      <AlertDialogContent>
        <AlertDialogHeader>
          <AlertDialogTitle>
            {{ isNewAgent ? 'Publish Agent' : 'Publish Changes' }}
          </AlertDialogTitle>
          <AlertDialogDescription>
            <template v-if="isNewAgent">
              This will publish your agent for the first time. Once published, you can share it with
              other users.
            </template>
            <template v-else>
              This will update the published version of your agent. Users who have access to this
              agent will see the new version.
            </template>
            <div v-if="draft.documents?.length" class="mt-2 text-sm text-gray-600">
              Note: Document syncing may take a few moments to complete.
            </div>
          </AlertDialogDescription>
        </AlertDialogHeader>
        <AlertDialogFooter>
          <AlertDialogCancel>Cancel</AlertDialogCancel>
          <AlertDialogAction @click="onPublish">
            <i class="dku-icon-publish-16 w-4 h-4 mr-1" />
            {{ isNewAgent ? 'Publish' : 'Publish Changes' }}
          </AlertDialogAction>
        </AlertDialogFooter>
      </AlertDialogContent>
    </AlertDialog>

    <AlertDialog v-model:open="showDiscardDialog">
      <AlertDialogContent>
        <AlertDialogHeader>
          <AlertDialogTitle>Discard Changes</AlertDialogTitle>
          <AlertDialogDescription>
            This will revert all changes back to the last published version. Any modifications
            you've made will be lost.
          </AlertDialogDescription>
        </AlertDialogHeader>
        <AlertDialogFooter>
          <AlertDialogCancel>Cancel</AlertDialogCancel>
          <AlertDialogAction @click="onDiscardChanges"> Discard Changes </AlertDialogAction>
        </AlertDialogFooter>
      </AlertDialogContent>
    </AlertDialog>
    <AlertDialog v-model:open="showDiscardDialogBeforeLeaving">
      <AlertDialogContent>
        <AlertDialogHeader>
          <AlertDialogTitle>Agent not saved</AlertDialogTitle>
          <AlertDialogDescription>
            You have started creating an agent, but your changes haven’t been saved. If you leave
            now, the agent will not be created.
          </AlertDialogDescription>
        </AlertDialogHeader>
        <AlertDialogFooter>
          <AlertDialogCancel @click="confirmLeave"> Leave without saving </AlertDialogCancel>
          <AlertDialogAction @click="cancelLeave">Stay and continue editing</AlertDialogAction>
        </AlertDialogFooter>
      </AlertDialogContent>
    </AlertDialog>

    <!-- Share Agent Dialog -->
    <ShareAgent
      v-if="draft.id"
      :open="showShareDialog"
      :agentId="draft.id"
      :agentName="draft.name"
      @update:open="showShareDialog = $event"
    />
  </div>
</template>

<style scoped></style>
