<template>
  <div class="h-full flex flex-col">
    <!-- Header -->
    <div class="flex-shrink-0 bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60 border-b pb-4 px-4 sm:px-6 pt-4 sm:pt-6 mb-4">
      <div class="flex items-center justify-between mb-4">
        <div>
          <h1 class="text-2xl font-semibold">My Tasks</h1>
          <p class="text-sm text-muted-foreground mt-1">
            View and track your assigned tasks across all projects
          </p>
        </div>
        <div class="text-sm text-muted-foreground whitespace-nowrap">
          <span class="font-semibold">{{ tasks.length }}</span> total
          <span v-if="overdueTasks.length > 0" class="ml-3 text-destructive font-semibold">
            {{ overdueTasks.length }} overdue
          </span>
        </div>
      </div>

      <TaskTableToolbar
        v-model:status-filter="statusFilter"
        v-model:type-filter="typeFilter"
        v-model:episode-filter="episodeFilter"
        v-model:assignee-filter="assigneeFilter"
        v-model:context-filter="contextFilter"
        v-model:search="searchQuery"
        v-model:my-tasks-filter="myTasksFilter"
        v-model:project-filter="selectedProjectId"
        :column-visibility="columnVisibility"
        :episodes="episodes"
        :assignees="assignees"
        :task-types="taskTypes"
        :projects="projects"
        :current-user-id="currentUserId"
        :is-detail-panel-enabled="isDetailPanelEnabled"
        @update:column-visibility="updateColumnVisibility"
        @toggle-detail-panel="toggleDetailPanelEnabled"
      />
    </div>

    <!-- Task Count / Selection Count -->
    <div class="flex-shrink-0 flex items-center justify-between px-4 sm:px-6 mb-2">
      <div class="text-sm text-muted-foreground">
        <span v-if="selectedCount > 0" class="font-medium text-foreground">
          {{ selectedCount }} {{ selectedCount === 1 ? 'task' : 'tasks' }} selected
        </span>
        <span v-else-if="filteredTasks.length === tasks.length">
          {{ tasks.length }} {{ tasks.length === 1 ? 'task' : 'tasks' }}
        </span>
        <span v-else>
          {{ filteredTasks.length }} of {{ tasks.length }} {{ tasks.length === 1 ? 'task' : 'tasks' }}
        </span>
      </div>
    </div>

    <!-- Content -->
    <div class="flex-1 min-h-0">
      <div v-if="isLoading" class="flex items-center justify-center py-12 px-4 sm:px-6">
        <div class="flex items-center gap-2">
          <div class="animate-spin rounded-full h-6 w-6 border-b-2 border-primary"></div>
          <span class="text-muted-foreground">Loading tasks...</span>
        </div>
      </div>
      <div v-else-if="filteredTasks.length === 0" class="text-center py-12 px-4 sm:px-6">
        <ListTodo class="h-12 w-12 mx-auto text-muted-foreground mb-4" />
        <h3 class="text-lg font-semibold mb-2">No tasks found</h3>
        <p class="text-muted-foreground">
          {{ hasFilters ? 'Try adjusting your filters' : 'No tasks assigned to you' }}
        </p>
      </div>
      <TasksDataTable
        v-else
        :tasks="filteredTasks"
        :column-visibility="columnVisibility"
        :project-id="activeProjectId"
        :is-loading="isLoading"
        @row-click="handleRowClick"
        @row-double-click="handleRowDoubleClick"
        @context-menu="handleContextMenu"
        @selection-change="handleSelectionChange"
        @update:column-visibility="updateColumnVisibility"
        @status-updated="handleStatusUpdated"
        @bulk-status-change="(_, status) => handleBulkStatusUpdate(status)"
      />
    </div>

    <!-- Task Detail Panel (Desktop + Mobile) -->
    <DetailPanelOverlay
      :visible="!!showPanel"
      v-model:mobile-open="showMobileDetail"
    >
      <TaskDetailPanel
        v-if="selectedTask"
        :task-id="selectedTask?.id || 0"
        :is-open="true"
        @close="closeDetailPanel"
        @task-updated="handleTaskUpdated"
      />
    </DetailPanelOverlay>

    <!-- Context Menu for Bulk Actions -->
    <TaskBulkActionsMenu
      v-model:open="showContextMenu"
      :position="contextMenuPosition"
      :selected-count="selectedCount"
      :selected-tasks="selectedTasks"
      :project-members="projectMembers"
      @status-selected="handleBulkStatusUpdate"
      @assignee-selected="handleBulkAssignment"
    />
  </div>
</template>

<script setup lang="ts">
import { ref, computed, watch, onMounted } from 'vue'
import { ListTodo } from 'lucide-vue-next'
import type { VisibilityState } from '@tanstack/vue-table'
import DetailPanelOverlay from '@/components/shared/DetailPanelOverlay.vue'
import TaskTableToolbar from '@/components/task/TaskTableToolbar.vue'
import TaskDetailPanel from '@/components/task/TaskDetailPanel.vue'
import TaskBulkActionsMenu from '@/components/task/TaskBulkActionsMenu.vue'
import TasksDataTable from '@/components/task/TasksDataTable.vue'
import { taskService, type TaskListItem } from '@/services/task'
import { TaskStatus } from '@/services/asset'
import { episodeService, type Episode } from '@/services/episode'
import { projectService, type Project, type ProjectMember } from '@/services/project'
import { useAuthStore } from '@/stores/auth'
import { useTaskStatusesStore } from '@/stores/taskStatuses'
import { useDetailPanel } from '@/composables/useDetailPanel'
import { useToast } from '@/components/ui/toast/use-toast'

const { toast } = useToast()
const authStore = useAuthStore()
const taskStatusesStore = useTaskStatusesStore()

// Detail panel composable
const {
  isDetailPanelEnabled,
  selectedEntity: selectedTask,
  showMobileDetail,
  showPanel,
  toggleDetailPanelEnabled,
  closeDetailPanel,
  selectEntity: selectTask
} = useDetailPanel<TaskListItem>({
  isDialogOpen: () => showContextMenu.value,
  sessionStorageKey: 'myTasksView.detailPanelEnabled'
})

// State
const tasks = ref<TaskListItem[]>([])
const projects = ref<Project[]>([])
const episodes = ref<Episode[]>([])
const projectMembers = ref<ProjectMember[]>([])
const isLoading = ref(false)
const selectedProjectId = ref<number | null>(null)

// Context menu state
const showContextMenu = ref(false)
const contextMenuPosition = ref({ x: 0, y: 0 })

// Filters (client-side, matching TaskBrowser.vue's project-scoped Tasks page)
const statusFilter = ref<string[]>([])
const typeFilter = ref<string[]>([])
const episodeFilter = ref<number | null>(null)
const assigneeFilter = ref<number[]>([])
const contextFilter = ref<'all' | 'shots' | 'assets'>('all')
const searchQuery = ref('')
const myTasksFilter = ref(false)

// Table state
const columnVisibility = ref<VisibilityState>({})

// Selection state
const selectedTaskIds = ref<Set<number>>(new Set())

// Computed
const currentUserId = computed(() => authStore.user?.id || null)
const activeProjectId = computed(() => selectedProjectId.value ?? 0)

const overdueTasks = computed(() => {
  const now = new Date()
  return tasks.value.filter(task => {
    if (!task.deadline) return false
    const deadline = new Date(task.deadline)
    return deadline < now && task.status !== TaskStatus.APPROVED
  })
})

const assignees = computed(() => {
  const uniqueAssignees = new Map<number, { id: number; name: string }>()
  projectMembers.value.forEach((member) => {
    uniqueAssignees.set(member.user_id, {
      id: member.user_id,
      name: `${member.user_first_name} ${member.user_last_name}`,
    })
  })
  return Array.from(uniqueAssignees.values())
})

const taskTypes = computed(() => {
  const types = new Set<string>()
  tasks.value.forEach((task) => types.add(task.task_type))
  return Array.from(types).sort()
})

const selectedTasks = computed(() => {
  return filteredTasks.value.filter(task => selectedTaskIds.value.has(task.id))
})

const selectedCount = computed(() => selectedTaskIds.value.size)

const hasFilters = computed(() => {
  return (
    statusFilter.value.length > 0 ||
    typeFilter.value.length > 0 ||
    episodeFilter.value !== null ||
    assigneeFilter.value.length > 0 ||
    contextFilter.value !== 'all' ||
    searchQuery.value !== '' ||
    myTasksFilter.value
  )
})

const filteredTasks = computed(() => {
  let filtered = tasks.value

  if (searchQuery.value) {
    const query = searchQuery.value.toLowerCase()
    filtered = filtered.filter(
      (task) =>
        task.name.toLowerCase().includes(query) ||
        task.shot_name?.toLowerCase().includes(query) ||
        task.asset_name?.toLowerCase().includes(query)
    )
  }

  if (statusFilter.value.length > 0) {
    filtered = filtered.filter((task) => statusFilter.value.includes(task.status))
  }

  if (typeFilter.value.length > 0) {
    filtered = filtered.filter((task) => typeFilter.value.includes(task.task_type))
  }

  if (episodeFilter.value !== null) {
    filtered = filtered.filter((task) => task.episode_id === episodeFilter.value)
  }

  if (assigneeFilter.value.length > 0) {
    filtered = filtered.filter((task) =>
      task.assigned_user_id ? assigneeFilter.value.includes(task.assigned_user_id) : false
    )
  }

  if (contextFilter.value === 'shots') {
    filtered = filtered.filter((task) => task.shot_id !== null && task.shot_id !== undefined)
  } else if (contextFilter.value === 'assets') {
    filtered = filtered.filter((task) => task.asset_id !== null && task.asset_id !== undefined)
  }

  return filtered
})

// Methods
async function fetchMyTasks() {
  isLoading.value = true
  try {
    tasks.value = await taskService.getMyTasks(selectedProjectId.value ?? undefined)
  } catch (error) {
    console.error('Failed to fetch my tasks:', error)
    toast({
      title: 'Failed to load tasks',
      description: error instanceof Error ? error.message : 'An error occurred',
      variant: 'destructive',
    })
  } finally {
    isLoading.value = false
  }
}

async function fetchProjects() {
  try {
    projects.value = await projectService.getUserProjects()
  } catch (error) {
    console.error('Failed to fetch projects:', error)
  }
}

// Episode/assignee filters are project-scoped, so only populate them when a single
// project is selected (the toolbar already hides these filters when the list is empty).
async function fetchProjectScopedFilters() {
  if (selectedProjectId.value === null) {
    episodes.value = []
    projectMembers.value = []
    return
  }

  const projectId = selectedProjectId.value
  try {
    const [episodesResponse, membersResponse] = await Promise.all([
      episodeService.getEpisodes(projectId),
      projectService.getProjectMembers(projectId),
    ])
    episodes.value = episodesResponse
    projectMembers.value = membersResponse
  } catch (error) {
    console.error('Failed to fetch project-scoped filters:', error)
    episodes.value = []
    projectMembers.value = []
  }

  // Ensures the "Change Status" table-header dropdown has real per-project status
  // options ready as soon as a project is picked, not just once a row happens to render.
  try {
    await taskStatusesStore.fetchProjectStatuses(projectId)
  } catch (error) {
    console.error('Failed to fetch task statuses:', error)
  }
}

const handleRowClick = () => {
  // Row click is reserved for selection; only double-click opens the detail panel
  // (matches TaskBrowser.vue's convention for the project-scoped Tasks table).
}

const handleRowDoubleClick = (task: TaskListItem) => {
  selectTask(task)
  if (isDetailPanelEnabled.value && window.innerWidth < 1024) {
    showMobileDetail.value = true
  }
}

const handleTaskUpdated = () => {
  fetchMyTasks()
}

const handleStatusUpdated = (taskId: number, newStatus: string) => {
  const taskIndex = tasks.value.findIndex((t) => t.id === taskId)
  if (taskIndex !== -1) {
    const updatedTasks = [...tasks.value]
    updatedTasks[taskIndex] = {
      ...updatedTasks[taskIndex],
      status: newStatus as TaskStatus,
    }
    tasks.value = updatedTasks
  }
}

const handleSelectionChange = (taskIds: number[]) => {
  selectedTaskIds.value = new Set(taskIds)
}

const handleContextMenu = (event: MouseEvent, _tasks: TaskListItem[]) => {
  contextMenuPosition.value = { x: event.clientX, y: event.clientY }
  showContextMenu.value = true
}

const closeContextMenu = () => {
  showContextMenu.value = false
}

const handleBulkStatusUpdate = async (status: string) => {
  try {
    const taskIds = selectedTasks.value.map(task => task.id)
    if (taskIds.length === 0) return

    isLoading.value = true
    const result = await taskService.bulkUpdateStatus(taskIds, status)

    toast({
      title: 'Success',
      description: `${result.success_count} ${result.success_count === 1 ? 'task' : 'tasks'} updated`,
    })

    await fetchMyTasks()
    closeContextMenu()
  } catch (error) {
    console.error('Failed to update task status:', error)
    toast({
      title: 'Error',
      description: 'Failed to update tasks. Please try again.',
      variant: 'destructive',
    })
  } finally {
    isLoading.value = false
  }
}

const handleBulkAssignment = async (userId: number) => {
  try {
    const taskIds = selectedTasks.value.map(task => task.id)
    if (taskIds.length === 0) return

    isLoading.value = true
    const result = await taskService.bulkAssignTasks(taskIds, userId)

    toast({
      title: 'Success',
      description: `${result.success_count} ${result.success_count === 1 ? 'task' : 'tasks'} assigned`,
    })

    await fetchMyTasks()
    closeContextMenu()
  } catch (error) {
    console.error('Failed to assign tasks:', error)
    toast({
      title: 'Error',
      description: 'Failed to assign tasks. Please try again.',
      variant: 'destructive',
    })
  } finally {
    isLoading.value = false
  }
}

const updateColumnVisibility = (visibility: VisibilityState) => {
  columnVisibility.value = visibility
  sessionStorage.setItem('myTasksView.columnVisibility', JSON.stringify(visibility))
}

function loadColumnVisibility() {
  const saved = sessionStorage.getItem('myTasksView.columnVisibility')
  if (saved) {
    try {
      columnVisibility.value = JSON.parse(saved)
    } catch (error) {
      console.error('Failed to parse saved column visibility:', error)
    }
  }
}

// Clear selection when filters change
watch([statusFilter, typeFilter, episodeFilter, assigneeFilter, contextFilter, searchQuery], () => {
  selectedTaskIds.value = new Set()
})

// Refetch when the project filter changes (episode/assignee filters are project-scoped)
watch(selectedProjectId, () => {
  episodeFilter.value = null
  fetchMyTasks()
  fetchProjectScopedFilters()
})

// Lifecycle
onMounted(async () => {
  loadColumnVisibility()
  await Promise.all([fetchMyTasks(), fetchProjects()])
})
</script>
