<script setup lang="ts">
import { Doughnut, Bar, Line } from 'vue-chartjs'
import type { Task } from '~/services/dto/task'
import type { TaskStatus } from '~/services/dto/task-status'
import type { TaskPriority } from '~/services/dto/task-priority'
import type { TimeEntry } from '~/services/dto/time-entry'
import type { Project } from '~/services/dto/project'
import type { UserData } from '~/services/dto/user-data'
import { useTaskService } from '~/services/tasks'
import { useTaskStatusService } from '~/services/task-statuses'
import { useTaskPriorityService } from '~/services/task-priorities'
import { useTimeEntryService } from '~/services/time-entries'
import { useProjectService } from '~/services/projects'
import { useUserService } from '~/services/users'

const { t } = useI18n()
const auth = useAuthStore()

useHead({ title: t('dashboard.title') })

const taskService = useTaskService()
const statusService = useTaskStatusService()
const priorityService = useTaskPriorityService()
const timeEntryService = useTimeEntryService()
const projectService = useProjectService()
const userService = useUserService()

const allTasks = ref<Task[]>([])
const statuses = ref<TaskStatus[]>([])
const priorities = ref<TaskPriority[]>([])
const allTimeEntries = ref<TimeEntry[]>([])
const projects = ref<Project[]>([])
const users = ref<UserData[]>([])
const isLoading = ref(true)

// ── Filters ──

type PeriodKey = 'thisWeek' | 'lastWeek' | 'thisMonth' | 'lastMonth'

const selectedPeriod = ref<PeriodKey>('thisWeek')
const selectedProjectId = ref<number | null>(null)
const selectedUserId = ref<number | null>(null)

const periodOptions = computed(() => [
    { label: t('dashboard.periods.thisWeek'), value: 'thisWeek' },
    { label: t('dashboard.periods.lastWeek'), value: 'lastWeek' },
    { label: t('dashboard.periods.thisMonth'), value: 'thisMonth' },
    { label: t('dashboard.periods.lastMonth'), value: 'lastMonth' },
])

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

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

// ── Period date ranges ──

function getWeekRange(offset: number = 0) {
    const now = new Date()
    const day = now.getDay()
    const diffToMonday = day === 0 ? -6 : 1 - day
    const monday = new Date(now)
    monday.setDate(now.getDate() + diffToMonday + offset * 7)
    monday.setHours(0, 0, 0, 0)
    const sunday = new Date(monday)
    sunday.setDate(monday.getDate() + 6)
    sunday.setHours(23, 59, 59, 999)
    return { start: monday, end: sunday }
}

function getMonthRange(offset: number = 0) {
    const now = new Date()
    const start = new Date(now.getFullYear(), now.getMonth() + offset, 1)
    start.setHours(0, 0, 0, 0)
    const end = new Date(now.getFullYear(), now.getMonth() + offset + 1, 0)
    end.setHours(23, 59, 59, 999)
    return { start, end }
}

const dateRange = computed(() => {
    switch (selectedPeriod.value) {
        case 'thisWeek': return getWeekRange(0)
        case 'lastWeek': return getWeekRange(-1)
        case 'thisMonth': return getMonthRange(0)
        case 'lastMonth': return getMonthRange(-1)
    }
})

const isWeekPeriod = computed(() =>
    selectedPeriod.value === 'thisWeek' || selectedPeriod.value === 'lastWeek'
)

// ── Filtered data (client-side project filter) ──

const tasks = computed(() => {
    if (!selectedProjectId.value) return allTasks.value
    return allTasks.value.filter(t => t.project?.id === selectedProjectId.value)
})

const timeEntries = computed(() => {
    if (!selectedProjectId.value) return allTimeEntries.value
    return allTimeEntries.value.filter(e => e.project?.id === selectedProjectId.value)
})

// ── Data loading ──

async function loadReferenceData() {
    const [s, p, proj, u] = await Promise.all([
        statusService.getAll(),
        priorityService.getAll(),
        projectService.getAll(),
        userService.getAll(),
    ])
    statuses.value = s
    priorities.value = p
    projects.value = proj
    users.value = u
}

async function loadTasks() {
    allTasks.value = await taskService.getFiltered({ archived: false })
}

async function loadTimeEntries() {
    const params: { after: string; before: string; user?: number } = {
        after: dateRange.value.start.toISOString(),
        before: dateRange.value.end.toISOString(),
    }
    if (selectedUserId.value) {
        params.user = selectedUserId.value
    }
    allTimeEntries.value = await timeEntryService.getByDateRange(params)
}

async function loadAll() {
    isLoading.value = true
    try {
        await Promise.all([loadReferenceData(), loadTasks(), loadTimeEntries()])
    } finally {
        isLoading.value = false
    }
}

// Reload time entries when period or user changes (server-side filter)
watch([selectedPeriod, selectedUserId], () => {
    loadTimeEntries()
})

onMounted(() => loadAll())

// ── Helpers ──

function durationHours(entry: TimeEntry): number {
    const start = new Date(entry.startedAt)
    const end = entry.stoppedAt ? new Date(entry.stoppedAt) : new Date()
    return (end.getTime() - start.getTime()) / 3_600_000
}

function formatHours(h: number): string {
    const hours = Math.floor(h)
    const mins = Math.round((h - hours) * 60)
    return mins > 0 ? `${hours}h${String(mins).padStart(2, '0')}` : `${hours}h`
}

// ── KPI Stats ──

const totalHoursThisWeek = computed(() =>
    timeEntries.value.reduce((sum, e) => sum + durationHours(e), 0)
)

const myTasks = computed(() =>
    tasks.value.filter(t => t.assignee?.id === auth.user?.id)
)

const myTasksDone = computed(() =>
    myTasks.value.filter(t => t.status?.isFinal)
)

const unassignedTasks = computed(() =>
    tasks.value.filter(t => !t.assignee)
)

// ── Chart: Tasks by Status (Doughnut) ──

const tasksByStatusData = computed(() => {
    const sorted = [...statuses.value].sort((a, b) => a.position - b.position)
    const noStatus = tasks.value.filter(t => !t.status).length
    const labels = noStatus > 0 ? ['Backlog', ...sorted.map(s => s.label)] : sorted.map(s => s.label)
    const data = noStatus > 0
        ? [noStatus, ...sorted.map(s => tasks.value.filter(t => t.status?.id === s.id).length)]
        : sorted.map(s => tasks.value.filter(t => t.status?.id === s.id).length)
    const colors = noStatus > 0
        ? ['#9ca3af', ...sorted.map(s => s.color)]
        : sorted.map(s => s.color)

    return {
        labels,
        datasets: [{
            data,
            backgroundColor: colors,
            borderWidth: 0,
        }],
    }
})

// ── Chart: Tasks by Priority (Bar) ──

const tasksByPriorityData = computed(() => {
    const sorted = [...priorities.value]
    const noPriority = tasks.value.filter(t => !t.priority).length
    const labels = [...sorted.map(p => p.label), ...(noPriority > 0 ? [t('dashboard.noPriority')] : [])]
    const data = [...sorted.map(p => tasks.value.filter(t => t.priority?.id === p.id).length), ...(noPriority > 0 ? [noPriority] : [])]
    const colors = [...sorted.map(p => p.color), ...(noPriority > 0 ? ['#9ca3af'] : [])]

    return {
        labels,
        datasets: [{
            data,
            backgroundColor: colors,
            borderWidth: 0,
            borderRadius: 6,
        }],
    }
})

// ── Chart: Hours by Project (Doughnut) ──

const hoursByProjectData = computed(() => {
    const projectHours = new Map<number, { name: string; color: string; hours: number }>()
    let noProjectHours = 0

    for (const entry of timeEntries.value) {
        const h = durationHours(entry)
        if (entry.project) {
            const existing = projectHours.get(entry.project.id)
            if (existing) {
                existing.hours += h
            } else {
                projectHours.set(entry.project.id, {
                    name: entry.project.name,
                    color: entry.project.color || '#6366f1',
                    hours: h,
                })
            }
        } else {
            noProjectHours += h
        }
    }

    const entries = [...projectHours.values()].sort((a, b) => b.hours - a.hours)
    if (noProjectHours > 0) {
        entries.push({ name: t('dashboard.noProject'), color: '#9ca3af', hours: noProjectHours })
    }

    return {
        labels: entries.map(e => e.name),
        datasets: [{
            data: entries.map(e => Math.round(e.hours * 100) / 100),
            backgroundColor: entries.map(e => e.color),
            borderWidth: 0,
        }],
    }
})

// ── Chart: Hours by Day (Line) ──

const weekDayLabels = [
    t('dashboard.days.mon'),
    t('dashboard.days.tue'),
    t('dashboard.days.wed'),
    t('dashboard.days.thu'),
    t('dashboard.days.fri'),
    t('dashboard.days.sat'),
    t('dashboard.days.sun'),
]

const hoursByDayData = computed(() => {
    if (isWeekPeriod.value) {
        const dayHours = new Array(7).fill(0)
        for (const entry of timeEntries.value) {
            const start = new Date(entry.startedAt)
            const dayIndex = start.getDay() === 0 ? 6 : start.getDay() - 1
            dayHours[dayIndex] += durationHours(entry)
        }
        return {
            labels: weekDayLabels,
            datasets: [{
                label: t('dashboard.hoursWorked'),
                data: dayHours.map(h => Math.round(h * 100) / 100),
                borderColor: '#6366f1',
                backgroundColor: 'rgba(99, 102, 241, 0.1)',
                fill: true,
                tension: 0.3,
                pointBackgroundColor: '#6366f1',
                pointRadius: 4,
            }],
        }
    }

    // Month view: group by week number
    const { start, end } = dateRange.value
    const weekMap = new Map<string, number>()
    const weekLabels: string[] = []

    // Build week labels for the month
    const cursor = new Date(start)
    while (cursor <= end) {
        const weekStart = new Date(cursor)
        const weekEnd = new Date(cursor)
        weekEnd.setDate(weekEnd.getDate() + 6)
        if (weekEnd > end) weekEnd.setTime(end.getTime())
        const label = `${weekStart.getDate()}/${weekStart.getMonth() + 1} - ${weekEnd.getDate()}/${weekEnd.getMonth() + 1}`
        weekLabels.push(label)
        weekMap.set(label, 0)
        cursor.setDate(cursor.getDate() + 7)
        // Align to Monday
        const d = cursor.getDay()
        if (d !== 1) {
            cursor.setDate(cursor.getDate() + (d === 0 ? 1 : 8 - d))
        }
    }

    for (const entry of timeEntries.value) {
        const entryDate = new Date(entry.startedAt)
        for (let i = 0; i < weekLabels.length; i++) {
            const parts = weekLabels[i].split(' - ')
            const [sd, sm] = parts[0].split('/').map(Number)
            const [ed, em] = parts[1].split('/').map(Number)
            const ws = new Date(start.getFullYear(), sm - 1, sd)
            const we = new Date(start.getFullYear(), em - 1, ed, 23, 59, 59)
            if (entryDate >= ws && entryDate <= we) {
                weekMap.set(weekLabels[i], (weekMap.get(weekLabels[i]) ?? 0) + durationHours(entry))
                break
            }
        }
    }

    return {
        labels: weekLabels,
        datasets: [{
            label: t('dashboard.hoursWorked'),
            data: weekLabels.map(l => Math.round((weekMap.get(l) ?? 0) * 100) / 100),
            borderColor: '#6366f1',
            backgroundColor: 'rgba(99, 102, 241, 0.1)',
            fill: true,
            tension: 0.3,
            pointBackgroundColor: '#6366f1',
            pointRadius: 4,
        }],
    }
})

// ── Chart: Tasks by Project (Horizontal Bar) ──

const tasksByProjectData = computed(() => {
    const projectTasks = new Map<number, { name: string; color: string; count: number; done: number }>()

    for (const task of tasks.value) {
        if (!task.project) continue
        const existing = projectTasks.get(task.project.id)
        const isDone = task.status?.isFinal ?? false
        if (existing) {
            existing.count++
            if (isDone) existing.done++
        } else {
            projectTasks.set(task.project.id, {
                name: task.project.name,
                color: task.project.color || '#6366f1',
                count: 1,
                done: isDone ? 1 : 0,
            })
        }
    }

    const entries = [...projectTasks.values()].sort((a, b) => b.count - a.count)

    return {
        labels: entries.map(e => e.name),
        datasets: [
            {
                label: t('dashboard.inProgress'),
                data: entries.map(e => e.count - e.done),
                backgroundColor: entries.map(e => e.color),
                borderWidth: 0,
                borderRadius: 6,
            },
            {
                label: t('dashboard.done'),
                data: entries.map(e => e.done),
                backgroundColor: entries.map(e => e.color + '66'),
                borderWidth: 0,
                borderRadius: 6,
            },
        ],
    }
})

// ── Chart options ──

const doughnutOptions = {
    responsive: true,
    maintainAspectRatio: false,
    cutout: '65%',
    plugins: {
        legend: {
            position: 'bottom' as const,
            labels: {
                padding: 16,
                usePointStyle: true,
                pointStyle: 'circle',
                font: { size: 12 },
            },
        },
    },
}

const barOptions = {
    responsive: true,
    maintainAspectRatio: false,
    plugins: {
        legend: { display: false },
    },
    scales: {
        y: {
            beginAtZero: true,
            ticks: { stepSize: 1 },
            grid: { color: '#f3f4f6' },
        },
        x: {
            grid: { display: false },
        },
    },
}

const horizontalBarOptions = {
    responsive: true,
    maintainAspectRatio: false,
    indexAxis: 'y' as const,
    plugins: {
        legend: {
            position: 'bottom' as const,
            labels: {
                padding: 16,
                usePointStyle: true,
                pointStyle: 'circle',
                font: { size: 12 },
            },
        },
    },
    scales: {
        x: {
            beginAtZero: true,
            stacked: true,
            ticks: { stepSize: 1 },
            grid: { color: '#f3f4f6' },
        },
        y: {
            stacked: true,
            grid: { display: false },
        },
    },
}

const lineOptions = {
    responsive: true,
    maintainAspectRatio: false,
    plugins: {
        legend: { display: false },
        tooltip: {
            callbacks: {
                label: (ctx: any) => `${formatHours(ctx.raw)}`,
            },
        },
    },
    scales: {
        y: {
            beginAtZero: true,
            grid: { color: '#f3f4f6' },
            ticks: {
                callback: (value: any) => `${value}h`,
            },
        },
        x: {
            grid: { display: false },
        },
    },
}
</script>

<template>
    <div>
        <div class="sticky top-8 z-20 bg-white pb-4 sm:top-12">
            <h1 class="text-xl font-bold text-primary-500 sm:text-2xl">{{ $t('dashboard.title') }}</h1>

            <!-- Filters -->
            <div class="mt-4 flex flex-wrap gap-3">
                <MalioSelect
                    v-model="selectedPeriod"
                    :options="periodOptions"
                    :label="$t('dashboard.filters.period')"
                    min-width="!w-48"
                    text-field="text-sm"
                    text-value="text-sm"
                />
                <MalioSelect
                    v-model="selectedProjectId"
                    :options="projectOptions"
                    :label="$t('dashboard.filters.project')"
                    :empty-option-label="$t('dashboard.filters.allProjects')"
                    min-width="!w-40"
                    text-field="text-sm"
                    text-value="text-sm"
                />
                <MalioSelect
                    v-model="selectedUserId"
                    :options="userOptions"
                    :label="$t('dashboard.filters.user')"
                    :empty-option-label="$t('dashboard.filters.allUsers')"
                    min-width="!w-40"
                    text-field="text-sm"
                    text-value="text-sm"
                />
            </div>
        </div>

        <!-- Loading -->
        <div v-if="isLoading" class="mt-12 flex items-center justify-center">
            <p class="text-neutral-400">{{ $t('common.loading') }}</p>
        </div>

        <template v-else>
            <!-- KPI Cards -->
            <div class="mt-6 grid grid-cols-2 gap-4 lg:grid-cols-4">
                <div class="rounded-xl border border-neutral-100 bg-neutral-50 p-5">
                    <p class="text-xs font-medium uppercase tracking-wider text-neutral-400">
                        {{ $t('dashboard.stats.hoursPeriod') }}
                    </p>
                    <p class="mt-2 text-2xl font-bold text-neutral-900 sm:text-3xl">
                        {{ formatHours(totalHoursThisWeek) }}
                    </p>
                </div>
                <div class="rounded-xl border border-neutral-100 bg-neutral-50 p-5">
                    <p class="text-xs font-medium uppercase tracking-wider text-neutral-400">
                        {{ $t('dashboard.stats.myActiveTasks') }}
                    </p>
                    <p class="mt-2 text-2xl font-bold text-neutral-900 sm:text-3xl">
                        {{ myTasks.length - myTasksDone.length }}
                    </p>
                    <p class="mt-1 text-xs text-neutral-400">
                        {{ myTasksDone.length }} {{ $t('dashboard.stats.completed') }}
                    </p>
                </div>
                <div class="rounded-xl border border-neutral-100 bg-neutral-50 p-5">
                    <p class="text-xs font-medium uppercase tracking-wider text-neutral-400">
                        {{ $t('dashboard.stats.totalTasks') }}
                    </p>
                    <p class="mt-2 text-2xl font-bold text-neutral-900 sm:text-3xl">
                        {{ tasks.length }}
                    </p>
                    <p class="mt-1 text-xs text-neutral-400">
                        {{ unassignedTasks.length }} {{ $t('dashboard.stats.unassigned') }}
                    </p>
                </div>
                <div class="rounded-xl border border-neutral-100 bg-neutral-50 p-5">
                    <p class="text-xs font-medium uppercase tracking-wider text-neutral-400">
                        {{ $t('dashboard.stats.projects') }}
                    </p>
                    <p class="mt-2 text-2xl font-bold text-neutral-900 sm:text-3xl">
                        {{ projects.length }}
                    </p>
                    <p class="mt-1 text-xs text-neutral-400">
                        {{ users.length }} {{ $t('dashboard.stats.users') }}
                    </p>
                </div>
            </div>

            <!-- Charts Row 1 -->
            <div class="mt-8 grid gap-6 lg:grid-cols-2">
                <!-- Hours by Day (Line) -->
                <div class="rounded-xl border border-neutral-100 bg-neutral-50 p-5">
                    <h2 class="text-sm font-semibold text-neutral-700">
                        {{ $t('dashboard.charts.hoursByDay') }}
                    </h2>
                    <div class="mt-4 h-64">
                        <Line :data="hoursByDayData" :options="lineOptions" />
                    </div>
                </div>

                <!-- Hours by Project (Doughnut) -->
                <div class="rounded-xl border border-neutral-100 bg-neutral-50 p-5">
                    <h2 class="text-sm font-semibold text-neutral-700">
                        {{ $t('dashboard.charts.hoursByProject') }}
                    </h2>
                    <div class="mt-4 h-64">
                        <Doughnut
                            v-if="hoursByProjectData.labels.length > 0"
                            :data="hoursByProjectData"
                            :options="doughnutOptions"
                        />
                        <p v-else class="flex h-full items-center justify-center text-sm text-neutral-400">
                            {{ $t('dashboard.noData') }}
                        </p>
                    </div>
                </div>
            </div>

            <!-- Charts Row 2 -->
            <div class="mt-6 grid gap-6 lg:grid-cols-2">
                <!-- Tasks by Status (Doughnut) -->
                <div class="rounded-xl border border-neutral-100 bg-neutral-50 p-5">
                    <h2 class="text-sm font-semibold text-neutral-700">
                        {{ $t('dashboard.charts.tasksByStatus') }}
                    </h2>
                    <div class="mt-4 h-64">
                        <Doughnut
                            v-if="tasksByStatusData.labels.length > 0"
                            :data="tasksByStatusData"
                            :options="doughnutOptions"
                        />
                        <p v-else class="flex h-full items-center justify-center text-sm text-neutral-400">
                            {{ $t('dashboard.noData') }}
                        </p>
                    </div>
                </div>

                <!-- Tasks by Priority (Bar) -->
                <div class="rounded-xl border border-neutral-100 bg-neutral-50 p-5">
                    <h2 class="text-sm font-semibold text-neutral-700">
                        {{ $t('dashboard.charts.tasksByPriority') }}
                    </h2>
                    <div class="mt-4 h-64">
                        <Bar
                            v-if="tasksByPriorityData.labels.length > 0"
                            :data="tasksByPriorityData"
                            :options="barOptions"
                        />
                        <p v-else class="flex h-full items-center justify-center text-sm text-neutral-400">
                            {{ $t('dashboard.noData') }}
                        </p>
                    </div>
                </div>
            </div>

            <!-- Charts Row 3 -->
            <div class="mt-6">
                <!-- Tasks by Project (Horizontal Bar) -->
                <div class="rounded-xl border border-neutral-100 bg-neutral-50 p-5">
                    <h2 class="text-sm font-semibold text-neutral-700">
                        {{ $t('dashboard.charts.tasksByProject') }}
                    </h2>
                    <div class="mt-4" :style="{ height: Math.max(200, tasksByProjectData.labels.length * 40 + 60) + 'px' }">
                        <Bar
                            v-if="tasksByProjectData.labels.length > 0"
                            :data="tasksByProjectData"
                            :options="horizontalBarOptions"
                        />
                        <p v-else class="flex h-full items-center justify-center text-sm text-neutral-400">
                            {{ $t('dashboard.noData') }}
                        </p>
                    </div>
                </div>
            </div>
        </template>
    </div>
</template>
