<script setup lang="ts">
import { computed, ref, watch } from 'vue'
import { useDebounceFn } from '@vueuse/core'
import { API } from '@/Api'
import {
  Dialog,
  DialogContent,
  DialogHeader,
  DialogTitle,
  DialogFooter,
  DialogClose,
} from '@/components/ui/dialog'
import { Button } from '@/components/ui/button'
import ComboBox, { type Option } from '@/components/ui/select/ComboBox.vue'

type Project = { key: string; name: string }
type AgentRef = { id: string; name: string }

interface Props {
  open: boolean
  existingKeys: Set<string>
}
const props = defineProps<Props>()
const emit = defineEmits<{
  (e: 'update:open', v: boolean): void
  (e: 'selected', payload: { projectKey: string; projectName: string; agents: AgentRef[] }): void
}>()

const projects = ref<Project[]>([])
const projectQuery = ref('')
const debouncedProjectQuery = ref('')
const selectedProjectKey = ref<string | null>(null)
const selectedProjectName = ref<string>('')

const loadingProjects = ref(false)
const loadingAgents = ref(false)
const agents = ref<AgentRef[]>([])
const agentQuery = ref('')

const selectedIds = ref<Set<string>>(new Set())

const INITIAL_DISPLAY_LIMIT = 100

// Debounce the search query to improve performance
const updateDebouncedQuery = useDebounceFn((value: string) => {
  debouncedProjectQuery.value = value
  // Here you could trigger an API call if needed for server-side filtering
  // For now, we filter locally
}, 300)

// Watch for changes in projectQuery and update debounced version
watch(projectQuery, (newValue) => {
  updateDebouncedQuery(newValue)
})

// Transform projects to ComboBox options format
const projectOptions = computed<Option[]>(() => {
  return projects.value.map((p) => ({
    value: p.key,
    label: `${p.name} (${p.key})`,
  }))
})

const filteredProjectOptions = computed<Option[]>(() => {
  const q = debouncedProjectQuery.value.trim().toLowerCase()

  if (!q) {
    // Show only first N projects if no search query
    return projectOptions.value.slice(0, INITIAL_DISPLAY_LIMIT)
  }

  const filtered = projectOptions.value.filter(
    (opt) => opt.label.toLowerCase().includes(q) || opt.value.toLowerCase().includes(q)
  )

  // Limit filtered results too for performance
  return filtered.slice(0, 500)
})

const isShowingLimitedResults = computed(() => {
  const q = debouncedProjectQuery.value.trim().toLowerCase()
  if (!q && projectOptions.value.length > INITIAL_DISPLAY_LIMIT) {
    return true
  }
  if (q) {
    const totalMatches = projectOptions.value.filter(
      (opt) => opt.label.toLowerCase().includes(q) || opt.value.toLowerCase().includes(q)
    ).length
    return totalMatches > 500
  }
  return false
})

const projectHelpMessage = computed(() => {
  if (!isShowingLimitedResults.value) return undefined
  return `Showing ${filteredProjectOptions.value.length} of ${
    projectOptions.value.length
  } projects. ${
    projectQuery.value
      ? 'Refine your search to see more matches.'
      : 'Use search to find your project.'
  }`
})

function handleProjectSearch(query: string) {
  projectQuery.value = query
}

const filteredAgents = computed(() => {
  const q = agentQuery.value.trim().toLowerCase()
  const list = q
    ? agents.value.filter((a) => a.name.toLowerCase().includes(q) || a.id.toLowerCase().includes(q))
    : agents.value
  return list.map((a) => {
    const selected = selectedIds.value.has(a.id)
    const disabled = props.existingKeys.has(`${selectedProjectKey.value}::${a.id}`)
    return { ...a, selected, disabled }
  })
})

const newSelectedCount = computed(() => {
  if (!selectedProjectKey.value) return 0
  return Array.from(selectedIds.value).filter(
    (id) => !props.existingKeys.has(`${selectedProjectKey.value}::${id}`)
  ).length
})

const canConfirm = computed(() => !!selectedProjectKey.value && newSelectedCount.value > 0)

function close() {
  emit('update:open', false)
}

async function loadProjects() {
  loadingProjects.value = true
  try {
    const { data } = await API.listEnterpriseProjects()
    projects.value = data?.projects ?? []
  } finally {
    loadingProjects.value = false
  }
}

async function loadAgents(projectKey: string) {
  loadingAgents.value = true
  try {
    const { data } = await API.listEnterpriseProjectAgents(projectKey)
    agents.value = data?.agents ?? []
    selectedProjectName.value = data?.project?.name ?? projectKey
    selectedIds.value = new Set()
    agentQuery.value = ''
  } finally {
    loadingAgents.value = false
  }
}

watch(
  () => props.open,
  (o) => {
    if (o && projects.value.length === 0) loadProjects()
  }
)
watch(selectedProjectKey, (k) => {
  if (k) {
    // Set project name immediately from local data
    const project = projects.value.find((p) => p.key === k)
    if (project) {
      selectedProjectName.value = project.name
    }
    // Load agents (this may update the project name from API response)
    loadAgents(k)
  } else {
    selectedProjectName.value = ''
  }
})

function toggleSelection(id: string, disabled: boolean) {
  if (disabled) return

  const newSet = new Set(selectedIds.value)
  if (newSet.has(id)) {
    newSet.delete(id)
  } else {
    newSet.add(id)
  }
  selectedIds.value = newSet
}

function confirm() {
  if (!selectedProjectKey.value) return
  const chosen = agents.value.filter(
    (a) =>
      selectedIds.value.has(a.id) && !props.existingKeys.has(`${selectedProjectKey.value}::${a.id}`)
  )
  if (chosen.length === 0) return
  emit('selected', {
    projectKey: selectedProjectKey.value,
    projectName: selectedProjectName.value,
    agents: chosen,
  })
  close()
}

function isSelected(id: string): boolean {
  return selectedIds.value.has(id)
}
</script>

<template>
  <Dialog :open="open" @update:open="(v) => emit('update:open', v)">
    <DialogContent
      hide-close
      class="sm:max-w-[600px] max-h-[90vh] flex flex-col"
      @open-auto-focus="(e) => e.preventDefault()"
    >
      <DialogHeader class="flex-shrink-0">
        <DialogTitle>Choose a DSS project, then pick agents to add</DialogTitle>
      </DialogHeader>

      <div class="flex-1 flex flex-col min-h-0 space-y-3">
        <div class="flex-shrink-0 space-y-2">
          <label class="text-sm font-medium">Select project</label>
          <div class="flex flex-wrap items-center gap-2">
            <div class="flex-1 relative">
              <ComboBox
                v-model="selectedProjectKey"
                :options="filteredProjectOptions"
                :help-message="projectHelpMessage"
                placeholder="Search projects..."
                class="w-full"
                @search="handleProjectSearch"
              />
            </div>
            <span v-if="loadingProjects" class="text-xs text-muted-foreground">
              <i class="dku-icon-spin-16 mr-1" />Loading projects…
            </span>
          </div>
        </div>

        <div class="flex-1 flex flex-col min-h-[300px] overflow-y-auto">
          <div v-if="selectedProjectKey" class="flex flex-col space-y-3">
            <div
              class="flex-1 rounded-md overflow-y-auto h-[300px]"
              :class="filteredAgents.length === 0 ? '' : 'border border-border'"
            >
              <div v-if="filteredAgents.length > 0">
                <div
                  v-for="a in filteredAgents"
                  :key="a.id"
                  role="button"
                  tabindex="0"
                  class="flex items-center justify-between p-3 transition-colors bg-white border-b border-border admin-select-item"
                  :class="[
                    a.disabled ? 'opacity-50 cursor-not-allowed bg-gray-50' : 'cursor-pointer',
                    !a.disabled && isSelected(a.id) ? 'admin-selected' : '',
                  ]"
                  @click="toggleSelection(a.id, a.disabled)"
                  @keydown.enter.prevent="toggleSelection(a.id, a.disabled)"
                  @keydown.space.prevent="toggleSelection(a.id, a.disabled)"
                >
                  <div class="min-w-0 flex-1">
                    <div class="truncate text-sm font-medium">{{ a.name }}</div>
                  </div>

                  <div class="flex items-center gap-3 ml-4 flex-shrink-0">
                    <span v-if="a.disabled" class="text-xs text-muted-foreground whitespace-nowrap">
                      Already added
                    </span>
                    <i v-else-if="isSelected(a.id)" class="dku-icon-checkmark-16 admin-icon" />
                  </div>
                </div>
              </div>
            </div>

            <div v-if="loadingAgents" class="text-xs text-muted-foreground">
              <i class="dku-icon-spin-16 mr-1" />Loading agents…
            </div>
          </div>

          <div
            v-if="
              !selectedProjectKey ||
              (selectedProjectKey && filteredAgents.length === 0 && !loadingAgents)
            "
            class="flex-1 flex items-center justify-center bg-gray-50 p-8"
          >
            <p class="text-sm text-muted-foreground text-center">
              {{
                filteredAgents.length === 0 && selectedProjectKey
                  ? 'No agents found'
                  : 'Select a project to see its agents'
              }}
            </p>
          </div>
        </div>
      </div>

      <DialogFooter class="flex-shrink-0 mt-2">
        <DialogClose as-child>
          <Button variant="outline" size="lg" class="admin-btn admin-btn--secondary">Cancel</Button>
        </DialogClose>
        <Button
          size="lg"
          :disabled="!canConfirm"
          @click="confirm"
          class="admin-btn admin-btn--primary"
        >
          Add selected
        </Button>
      </DialogFooter>
    </DialogContent>
  </Dialog>
</template>

<style scoped>
.break-words {
  word-wrap: break-word;
  word-break: break-word;
  overflow-wrap: break-word;
}
</style>
