<template>
    <div class="flex min-h-0 flex-1 flex-col">
        <div ref="pageHeaderEl" class="flex-shrink-0">
            <PageHeader>
                Suivi des temps
                <template #actions>
                    <MalioButton
                        icon-name="mdi:plus"
                        icon-position="left"
                        button-class="shrink-0"
                        @click="openCreateDrawer()"
                    >
                        <span class="hidden sm:inline">Ajouter une Activité</span>
                        <span class="sm:hidden">Activité</span>
                    </MalioButton>
                </template>
                <template #subheader>
                    <div class="relative z-30 mt-4 flex flex-wrap items-center gap-3 sm:gap-4">
                        <div class="flex shrink-0 items-center gap-1 h-8">
                            <MalioButtonIcon
                                icon="mdi:chevron-left"
                                aria-label="Précédent"
                                variant="ghost"
                                @click="navigatePrev"
                            />
                            <DateFilter v-model="selectedDateFilter" :picker-mode="viewMode === 'day' ? 'day' : 'week'" />
                            <h2 class="shrink-0 whitespace-nowrap text-lg font-bold leading-8 text-orange-500">
                                {{ currentMonthLabel }}
                            </h2>
                            <MalioButtonIcon
                                icon="mdi:chevron-right"
                                aria-label="Suivant"
                                variant="ghost"
                                @click="navigateNext"
                            />
                        </div>

                        <div class="flex items-center rounded-full bg-neutral-100 p-1">
                            <button
                                v-for="mode in (['week', 'day', 'list'] as const)"
                                :key="mode"
                                class="rounded-full px-4 py-1.5 text-sm font-semibold transition-all"
                                :class="viewMode === mode
                                    ? 'bg-primary-500 text-white shadow-sm'
                                    : 'text-neutral-500 hover:text-neutral-700'"
                                @click="viewMode = mode"
                            >
                                {{ mode === 'week' ? 'Semaine' : mode === 'day' ? 'Jour' : 'Liste' }}
                            </button>
                        </div>

                        <div class="[&>div]:!mt-0">
                            <MalioSelect
                                v-model="selectedUserId"
                                :options="userOptions"
                                group-class="!w-36 sm:!w-44"
                                text-field="text-sm"
                                text-value="text-sm"
                                label="User"
                                empty-option-label="Tous"
                            />
                        </div>

                        <div class="[&>div]:!mt-0">
                            <MalioSelect
                                v-model="selectedProjectId"
                                :options="projectOptions"
                                empty-option-label="Tous"
                                label="Projet"
                                group-class="!w-36 sm:!w-44"
                                text-field="text-sm"
                                text-value="text-sm"
                            />
                        </div>

                        <div class="[&>div]:!mt-0">
                            <MalioSelect
                                v-model="selectedTagId"
                                :options="tagOptions"
                                empty-option-label="Tous"
                                label="Tag"
                                group-class="!w-36 sm:!w-44"
                                text-field="text-sm"
                                text-value="text-sm"
                            />
                        </div>

                        <MalioButton
                            :label="$t('timeEntries.export')"
                            variant="secondary"
                            icon-name="mdi:download"
                            icon-position="left"
                            button-class="w-auto px-4"
                            @click="exportDrawerOpen = true"
                        />
                    </div>
                </template>
            </PageHeader>
        </div>

        <div class="relative z-0 -mb-24 min-h-0 flex-1">
            <TimeEntryList
                v-if="viewMode === 'list'"
                :entries="filteredEntries"
                @edit-entry="openEditDrawer"
                @delete-entry="onDelete"
            />
            <TimeTrackingCalendar
                v-else
                :entries="filteredEntries"
                :start-date="startDate"
                :view-mode="viewMode"
                :sticky-offset="pageHeaderHeight"
                @edit-entry="openEditDrawer"
                @create-entry="openCreateDrawer"
                @move-entry="onMoveEntry"
                @resize-entry="onResizeEntry"
                @contextmenu="onContextMenu"
            />
        </div>

        <TimeEntryDrawer
            v-model="drawerOpen"
            :entry="editingEntry"
            :prefill-started-at="prefillStartedAt"
            :users="users"
            :projects="projects"
            :tags="tags"
            @saved="loadEntries"
        />

        <TimeEntryContextMenu
            :visible="contextMenu.visible"
            :x="contextMenu.x"
            :y="contextMenu.y"
            :entry="contextMenu.entry"
            :can-paste="!!clipboard"
            @close="contextMenu.visible = false"
            @copy="onCopy"
            @paste="onPaste"
            @delete="onDelete"
        />

        <TimeTrackingExportDrawer
            v-model="exportDrawerOpen"
            :users="users"
            :projects="projects"
            :tags="tags"
            :clients="clients"
            @export="onExport"
        />
    </div>
</template>

<script setup lang="ts">
import type { TimeEntry } from '~/modules/time-tracking/services/dto/time-entry'
import type { UserData } from '~/services/dto/user-data'
import type { Project } from '~/modules/project-management/services/dto/project'
import type { TaskTag } from '~/modules/project-management/services/dto/task-tag'
import type { Client } from '~/modules/directory/services/dto/client'
import { useTimeEntryService } from '~/modules/time-tracking/services/time-entries'
import type { HydraCollection } from '~/utils/api'
import { extractHydraMembers } from '~/utils/api'

useHead({ title: 'Suivi des temps' })

const authStore = useAuthStore()
const timeEntryService = useTimeEntryService()

const viewMode = ref<'week' | 'day' | 'list'>('week')
const startDate = ref(getMonday(new Date()))
const selectedUserId = ref<number | null>(authStore.user?.id ?? null)
const selectedTagId = ref<number | null>(null)
const selectedProjectId = ref<number | null>(null)
const selectedDateFilter = ref<Date | [Date, Date] | null>(null)

const entries = ref<TimeEntry[]>([])
const users = ref<UserData[]>([])
const projects = ref<Project[]>([])
const tags = ref<TaskTag[]>([])
const clients = ref<Client[]>([])
const exportDrawerOpen = ref(false)

const drawerOpen = ref(false)
const editingEntry = ref<TimeEntry | null>(null)
const prefillStartedAt = ref<string | null>(null)
const clipboard = ref<TimeEntry | null>(null)
const pageHeaderEl = ref<HTMLElement | null>(null)
const pageHeaderHeight = ref(0)

const contextMenu = reactive({
    visible: false,
    x: 0,
    y: 0,
    entry: null as TimeEntry | null,
    targetDate: null as string | null,
})

const currentMonthLabel = computed(() => {
    const d = startDate.value
    const months = ['Janvier', 'Février', 'Mars', 'Avril', 'Mai', 'Juin', 'Juillet', 'Août', 'Septembre', 'Octobre', 'Novembre', 'Décembre']
    return `${months[d.getMonth()]} ${d.getFullYear()}`
})

const userOptions = computed(() =>
    users.value.map(u => ({ label: u.username, value: u.id }))
)

const projectOptions = computed(() =>
    projects.value.map(p => ({ label: p.name, value: p.id }))
)

const tagOptions = computed(() =>
    tags.value.map(t => ({ label: t.label, value: t.id }))
)

let pageHeaderResizeObserver: ResizeObserver | null = null

function updatePageHeaderHeight() {
    pageHeaderHeight.value = pageHeaderEl.value?.offsetHeight ?? 0
}

const filteredEntries = computed(() => entries.value)

function getMonday(d: Date): Date {
    const date = new Date(d)
    const day = date.getDay()
    const diff = date.getDate() - day + (day === 0 ? -6 : 1)
    date.setDate(diff)
    date.setHours(0, 0, 0, 0)
    return date
}

function navigatePrev() {
    const d = new Date(startDate.value)
    if (viewMode.value === 'day') {
        d.setDate(d.getDate() - 1)
        startDate.value = d
    } else if (viewMode.value === 'list') {
        d.setMonth(d.getMonth() - 1)
        d.setDate(1)
        d.setHours(0, 0, 0, 0)
        startDate.value = d
    } else {
        d.setDate(d.getDate() - 7)
        startDate.value = getMonday(d)
    }
    loadEntries()
}

function navigateNext() {
    const d = new Date(startDate.value)
    if (viewMode.value === 'day') {
        d.setDate(d.getDate() + 1)
        startDate.value = d
    } else if (viewMode.value === 'list') {
        d.setMonth(d.getMonth() + 1)
        d.setDate(1)
        d.setHours(0, 0, 0, 0)
        startDate.value = d
    } else {
        d.setDate(d.getDate() + 7)
        startDate.value = getMonday(d)
    }
    loadEntries()
}

function openCreateDrawer(startedAt?: string) {
    editingEntry.value = null
    prefillStartedAt.value = startedAt ?? null
    drawerOpen.value = true
}

function openEditDrawer(entry: TimeEntry) {
    editingEntry.value = entry
    prefillStartedAt.value = null
    drawerOpen.value = true
}

async function onMoveEntry(entry: TimeEntry, newStartedAt: string, newStoppedAt: string) {
    // Optimistic update — instant visual feedback
    const idx = entries.value.findIndex((e) => e.id === entry.id)
    if (idx === -1) return
    const original = entries.value[idx]!
    entries.value[idx] = { ...original, startedAt: newStartedAt, stoppedAt: newStoppedAt }

    try {
        await timeEntryService.update(entry.id, { startedAt: newStartedAt, stoppedAt: newStoppedAt })
    } catch {
        entries.value[idx] = original
    }
}

async function onResizeEntry(entry: TimeEntry, newStartedAt: string, newStoppedAt: string) {
    // Optimistic update — instant visual feedback
    const idx = entries.value.findIndex((e) => e.id === entry.id)
    if (idx === -1) return
    const original = entries.value[idx]!
    entries.value[idx] = { ...original, startedAt: newStartedAt, stoppedAt: newStoppedAt }

    try {
        await timeEntryService.update(entry.id, { startedAt: newStartedAt, stoppedAt: newStoppedAt })
    } catch {
        entries.value[idx] = original
    }
}

function onContextMenu(event: MouseEvent, entry: TimeEntry | null) {
    contextMenu.visible = true
    contextMenu.x = event.clientX
    contextMenu.y = event.clientY
    contextMenu.entry = entry
}

function onCopy(entry: TimeEntry) {
    clipboard.value = entry
}

async function onPaste() {
    if (!clipboard.value) return
    const { create } = useTimeEntryService()
    await create({
        title: clipboard.value.title ?? undefined,
        description: clipboard.value.description ?? undefined,
        startedAt: clipboard.value.startedAt,
        stoppedAt: clipboard.value.stoppedAt ?? undefined,
        user: `/api/users/${selectedUserId.value}`,
        project: clipboard.value.project ? `/api/projects/${clipboard.value.project.id}` : null,
        tags: clipboard.value.tags.map((t) => `/api/task_tags/${t.id}`),
    })
    await loadEntries()
}

onBeforeUnmount(() => {
    pageHeaderResizeObserver?.disconnect()
})

async function onDelete(entry: TimeEntry) {
    await timeEntryService.remove(entry.id)
    await loadEntries()
}

async function onExport(params: {
    after: string
    before: string
    users?: number[]
    projects?: number[]
    client?: number
    tags?: number[]
}) {
    const toast = useToast()
    const { t } = useNuxtApp().$i18n as { t: (key: string) => string }

    toast.info({ message: t('timeEntries.exportLoading') })

    try {
        const result = await timeEntryService.downloadExport(params)

        const url = URL.createObjectURL(result.blob)
        const a = document.createElement('a')
        a.href = url
        a.download = result.filename
        document.body.appendChild(a)
        a.click()
        document.body.removeChild(a)
        URL.revokeObjectURL(url)

        toast.success({ message: t('timeEntries.exportSuccess') })
    } catch {
        toast.error({ message: t('timeEntries.exportError') })
    }
}

async function loadEntries() {
    const end = new Date(startDate.value)
    if (viewMode.value === 'day') {
        end.setDate(end.getDate() + 1)
    } else if (viewMode.value === 'list') {
        end.setMonth(end.getMonth() + 1)
    } else {
        end.setDate(end.getDate() + 7)
    }

    entries.value = await timeEntryService.getByDateRange({
        after: startDate.value.toISOString(),
        before: end.toISOString(),
        user: selectedUserId.value ?? undefined,
        project: selectedProjectId.value ?? undefined,
        tag: selectedTagId.value ?? undefined,
    })
}

async function loadReferenceData() {
    const api = useApi()

    const [usersData, projectsData, typesData, clientsData] = await Promise.all([
        api.get<HydraCollection<UserData>>('/users'),
        api.get<HydraCollection<Project>>('/projects'),
        api.get<HydraCollection<TaskTag>>('/task_tags'),
        api.get<HydraCollection<Client>>('/clients'),
    ])

    users.value = extractHydraMembers(usersData)
    projects.value = extractHydraMembers(projectsData)
    tags.value = extractHydraMembers(typesData)
    clients.value = extractHydraMembers(clientsData)
}

onMounted(async () => {
    updatePageHeaderHeight()

    if (pageHeaderEl.value && typeof ResizeObserver !== 'undefined') {
        pageHeaderResizeObserver = new ResizeObserver(() => {
            updatePageHeaderHeight()
        })
        pageHeaderResizeObserver.observe(pageHeaderEl.value)
    }

    await loadReferenceData()
    await loadEntries()
})

watch(viewMode, () => {
    selectedDateFilter.value = null
    if (viewMode.value === 'day') {
        // keep current date
    } else if (viewMode.value === 'list') {
        const d = new Date(startDate.value)
        d.setDate(1)
        d.setHours(0, 0, 0, 0)
        startDate.value = d
    } else {
        startDate.value = getMonday(startDate.value)
    }
    loadEntries()
})

watch([selectedUserId, selectedProjectId, selectedTagId], () => {
    loadEntries()
})

watch(selectedDateFilter, (val) => {
    if (!val) return
    if (Array.isArray(val)) {
        startDate.value = getMonday(val[0])
        viewMode.value = 'week'
    } else {
        startDate.value = val
        viewMode.value = 'day'
    }
    loadEntries()
})
</script>
