<template>
  <Popover v-model:open="isOpen">
    <!-- pointer-events: none — this is a positioning reference only. Without it, it's a
         real (if invisible) 1x1px element sitting exactly at the original right-click
         point, so a second right-click at the same spot hits *it* directly instead of
         passing through to the row (or anything else) underneath. -->
    <PopoverAnchor
      :style="{
        position: 'fixed',
        left: `${props.position.x}px`,
        top: `${props.position.y}px`,
        width: '1px',
        height: '1px',
        pointerEvents: 'none',
      }"
    />
    <PopoverContent
      class="w-56 p-1"
      :side="'bottom'"
      :align="'start'"
      @interact-outside="handleInteractOutside"
    >
    <!-- Plain native div, not a component prop-forward chain — guarantees the
         listener actually reaches the DOM to suppress the browser's own menu
         when right-clicking anywhere on this (already-a-right-click-triggered) menu. -->
    <div @contextmenu.prevent>
      <!-- Header showing selection count -->
      <div class="px-2 py-1.5 text-sm font-semibold text-muted-foreground border-b mb-1">
        {{ selectedCount }} {{ selectedCount === 1 ? 'task' : 'tasks' }} selected
      </div>

      <!-- Validation warning if tasks from multiple projects -->
      <div v-if="hasMultipleProjects" class="px-2 py-1.5 text-xs text-destructive bg-destructive/10 rounded-sm mb-1">
        Selected tasks are from different projects
      </div>

      <!-- Set Status submenu -->
      <DropdownMenu>
        <DropdownMenuTrigger as-child>
          <button
            :disabled="isProcessing || hasMultipleProjects || isLoadingStatuses"
            class="w-full text-left px-2 py-1.5 text-sm hover:bg-accent hover:text-accent-foreground rounded-sm cursor-pointer disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-between"
          >
            <span>Set Status</span>
            <ChevronRight class="h-4 w-4" />
          </button>
        </DropdownMenuTrigger>
        <DropdownMenuContent class="w-48" side="right" align="start">
          <div @contextmenu.prevent>
            <!-- Loading state -->
            <div v-if="isLoadingStatuses" class="px-2 py-1.5 text-sm text-muted-foreground">
              Loading statuses...
            </div>

            <!-- System statuses -->
            <template v-else>
              <div v-if="systemStatuses.length > 0" class="px-2 py-1 text-xs font-semibold text-muted-foreground">
                System Statuses
              </div>
              <DropdownMenuItem
                v-for="status in systemStatuses"
                :key="status.id"
                :disabled="isProcessing"
                @click="handleStatusSelected(status.id)"
              >
                <TaskStatusBadge :status="status" compact />
              </DropdownMenuItem>

              <!-- Divider if both system and custom statuses exist -->
              <div v-if="systemStatuses.length > 0 && customStatuses.length > 0" class="h-px bg-border my-1" />

              <!-- Custom statuses -->
              <div v-if="customStatuses.length > 0" class="px-2 py-1 text-xs font-semibold text-muted-foreground">
                Custom Statuses
              </div>
              <DropdownMenuItem
                v-for="status in customStatuses"
                :key="status.id"
                :disabled="isProcessing"
                @click="handleStatusSelected(status.id)"
              >
                <TaskStatusBadge :status="status" compact />
              </DropdownMenuItem>
            </template>
          </div>
        </DropdownMenuContent>
      </DropdownMenu>

      <!-- Divider -->
      <div class="h-px bg-border my-1" />

      <!-- Assign To submenu -->
      <DropdownMenu @update:open="onAssignMenuOpenChange">
        <DropdownMenuTrigger as-child>
          <button
            :disabled="isProcessing || hasMultipleProjects"
            class="w-full text-left px-2 py-1.5 text-sm hover:bg-accent hover:text-accent-foreground rounded-sm cursor-pointer disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-between"
          >
            <span>Assign To</span>
            <ChevronRight class="h-4 w-4" />
          </button>
        </DropdownMenuTrigger>
        <DropdownMenuContent class="w-56 p-0" side="right" align="start">
          <div @contextmenu.prevent>
          <div class="p-1.5 border-b" @keydown.stop @click.stop>
            <div class="relative">
              <Search class="absolute left-2 top-1/2 -translate-y-1/2 h-3 w-3 text-muted-foreground" />
              <Input
                v-model="assigneeSearchQuery"
                placeholder="Search members..."
                class="h-7 pl-7 text-xs"
              />
            </div>
          </div>
          <div class="max-h-56 overflow-y-auto p-1">
            <div v-if="projectMembers.length === 0" class="px-2 py-1.5 text-sm text-muted-foreground">
              No members available
            </div>
            <div v-else-if="filteredMembers.length === 0" class="px-2 py-1.5 text-sm text-muted-foreground">
              No matching members
            </div>
            <template v-else>
              <div v-if="recommendedMembers.length > 0" class="px-2 py-1 text-xs font-semibold text-muted-foreground">
                Recommended
              </div>
              <DropdownMenuItem
                v-for="member in recommendedMembers"
                :key="member.user_id"
                :disabled="isProcessing"
                @click="handleAssigneeSelected(member.user_id)"
                class="flex items-center gap-2"
              >
                <Avatar class="h-6 w-6 flex-shrink-0">
                  <AvatarImage :src="getAvatarUrl(member.user_avatar_url, member.user_first_name, member.user_last_name)" />
                  <AvatarFallback class="text-[9px]">{{ getMemberInitials(member) }}</AvatarFallback>
                </Avatar>
                <div class="flex flex-col min-w-0">
                  <span class="truncate">{{ member.user_first_name }} {{ member.user_last_name }}</span>
                  <span v-if="member.department_role" class="text-[10px] text-muted-foreground capitalize">{{ member.department_role }}</span>
                </div>
              </DropdownMenuItem>

              <div v-if="recommendedMembers.length > 0 && otherMembers.length > 0" class="h-px bg-border my-1" />

              <div v-if="otherMembers.length > 0" class="px-2 py-1 text-xs font-semibold text-muted-foreground">
                {{ recommendedMembers.length > 0 ? 'All Members' : 'Members' }}
              </div>
              <DropdownMenuItem
                v-for="member in otherMembers"
                :key="member.user_id"
                :disabled="isProcessing"
                @click="handleAssigneeSelected(member.user_id)"
                class="flex items-center gap-2"
              >
                <Avatar class="h-6 w-6 flex-shrink-0">
                  <AvatarImage :src="getAvatarUrl(member.user_avatar_url, member.user_first_name, member.user_last_name)" />
                  <AvatarFallback class="text-[9px]">{{ getMemberInitials(member) }}</AvatarFallback>
                </Avatar>
                <div class="flex flex-col min-w-0">
                  <span class="truncate">{{ member.user_first_name }} {{ member.user_last_name }}</span>
                  <span v-if="member.department_role" class="text-[10px] text-muted-foreground capitalize">{{ member.department_role }}</span>
                </div>
              </DropdownMenuItem>
            </template>
          </div>
          </div>
        </DropdownMenuContent>
      </DropdownMenu>
    </div>
    </PopoverContent>
  </Popover>
</template>

<script setup lang="ts">
import { ref, watch, computed, onMounted } from 'vue'
import {
  Popover,
  PopoverAnchor,
  PopoverContent,
} from '@/components/ui/popover'
import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuTrigger,
} from '@/components/ui/dropdown-menu'
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'
import { Input } from '@/components/ui/input'
import TaskStatusBadge from '@/components/task/TaskStatusBadge.vue'
import { ChevronRight, Search } from 'lucide-vue-next'
import type { ProjectMember } from '@/services/project'
import type { Task } from '@/services/task'
import { customTaskStatusService, type CustomTaskStatus, type SystemTaskStatus } from '@/services/customTaskStatus'
import { useTaskStatusesStore } from '@/stores/taskStatuses'
import { useAvatarUrl } from '@/composables/useAvatarUrl'

interface Props {
  open: boolean
  position: { x: number; y: number }
  selectedCount: number
  selectedTasks: Task[]
  projectMembers: ProjectMember[]
  isProcessing?: boolean
}

interface Emits {
  (e: 'update:open', value: boolean): void
  (e: 'status-selected', status: string): void
  (e: 'assignee-selected', userId: number): void
}

const props = withDefaults(defineProps<Props>(), {
  isProcessing: false,
})

const emit = defineEmits<Emits>()

// Use the shared task statuses store
const taskStatusesStore = useTaskStatusesStore()
const { getAvatarUrl } = useAvatarUrl()

// Local state for menu open/close
const isOpen = ref(props.open)

// Assign To search state
const assigneeSearchQuery = ref('')

// Computed properties
const hasMultipleProjects = computed(() => {
  if (props.selectedTasks.length === 0) return false
  const projectIds = new Set(props.selectedTasks.map(task => task.project_id))
  return projectIds.size > 1
})

const currentProjectId = computed(() => {
  if (props.selectedTasks.length === 0) return null
  return props.selectedTasks[0].project_id
})

// Get loading state from store
const isLoadingStatuses = computed(() => {
  return currentProjectId.value ? taskStatusesStore.isLoading(currentProjectId.value) : false
})

// Get status options from store
const systemStatuses = computed(() => {
  if (!currentProjectId.value) return []
  const statuses = taskStatusesStore.getProjectStatuses(currentProjectId.value)
  return statuses?.system_statuses || []
})

const customStatuses = computed(() => {
  if (!currentProjectId.value) return []
  const statuses = taskStatusesStore.getProjectStatuses(currentProjectId.value)
  return statuses?.statuses || []
})

// Task types among the selected tasks, used to recommend project members whose
// department matches. "composite" (department) vs. "compositing" (task type) is
// the one known vocabulary mismatch, handled explicitly below.
const selectedTaskTypes = computed(() => new Set(props.selectedTasks.map(task => task.task_type)))

const departmentMatchesSelection = (departmentRole: string | undefined | null): boolean => {
  if (!departmentRole) return false
  for (const taskType of selectedTaskTypes.value) {
    if (departmentRole === taskType) return true
    if (departmentRole === 'composite' && taskType === 'compositing') return true
  }
  return false
}

const filteredMembers = computed(() => {
  const query = assigneeSearchQuery.value.toLowerCase().trim()
  if (!query) return props.projectMembers

  return props.projectMembers.filter(member => {
    const fullName = `${member.user_first_name} ${member.user_last_name}`.toLowerCase()
    const department = member.department_role?.toLowerCase() || ''
    return fullName.includes(query) || department.includes(query)
  })
})

// Members whose department matches the selected task(s) are surfaced first, but
// everyone remains selectable — department_role is often unset, and a hard filter
// would leave the list empty for many projects.
const recommendedMembers = computed(() =>
  filteredMembers.value.filter(member => departmentMatchesSelection(member.department_role))
)

const otherMembers = computed(() =>
  filteredMembers.value.filter(member => !departmentMatchesSelection(member.department_role))
)

const getMemberInitials = (member: ProjectMember): string => {
  const first = member.user_first_name?.charAt(0) || ''
  const last = member.user_last_name?.charAt(0) || ''
  return (first + last).toUpperCase()
}

const onAssignMenuOpenChange = (open: boolean) => {
  if (!open) {
    assigneeSearchQuery.value = ''
  }
}

// Methods
const fetchStatuses = async () => {
  if (!currentProjectId.value || hasMultipleProjects.value) {
    return
  }

  try {
    await taskStatusesStore.fetchProjectStatuses(currentProjectId.value)
  } catch (error) {
    console.error('Failed to fetch task statuses:', error)
  }
}

const handleStatusSelected = (status: string) => {
  emit('status-selected', status)
  isOpen.value = false
}

const handleAssigneeSelected = (userId: number) => {
  emit('assignee-selected', userId)
  isOpen.value = false
}

const handleInteractOutside = () => {
  isOpen.value = false
}

// Watch for prop changes
watch(
  () => props.open,
  (newValue) => {
    isOpen.value = newValue
    // Fetch statuses when menu opens
    if (newValue && currentProjectId.value && !hasMultipleProjects.value) {
      fetchStatuses()
    }
  }
)

// Emit changes to parent
watch(isOpen, (newValue) => {
  emit('update:open', newValue)
})

// Watch for selected tasks changes to refetch statuses if project changes
watch(
  () => currentProjectId.value,
  (newProjectId, oldProjectId) => {
    if (newProjectId && newProjectId !== oldProjectId && isOpen.value) {
      fetchStatuses()
    }
  }
)

// Fetch statuses on mount if menu is already open
onMounted(() => {
  if (isOpen.value && currentProjectId.value && !hasMultipleProjects.value) {
    fetchStatuses()
  }
})
</script>
