<template>
    <v-card>
        <v-card-title class="d-flex ga-3 flex-wrap align-center">
            <span>Activities</span>
            <v-spacer />

            <v-menu v-model="dateMenu" :close-on-content-click="false" transition="scale-transition" offset-y>
                <template #activator="{ props }">
                    <v-text-field
                        v-bind="props"
                        :model-value="formattedDate"
                        density="compact"
                        variant="outlined"
                        label="Date"
                        hide-details
                        readonly
                        style="max-width:180px"
                    />
                </template>
                <v-date-picker
                    v-model="selectedDate"
                    first-day-of-week="1"
                    show-adjacent-months
                    @update:modelValue="dateMenu = false"
                />
            </v-menu>

            <v-autocomplete
                v-model="selectedUserId"
                v-model:search="memberSearch"
                :items="userOptions"
                item-title="label"
                item-value="id"
                label="Member"
                density="compact"
                variant="outlined"
                hide-details
                :disabled="!canViewAllTracking"
                :loading="membersLoading"
                no-filter
                clearable
                style="max-width:280px"
            />
        </v-card-title>

        <v-card-text class="pt-0">
            <v-row class="mb-3">
                <v-col cols="12" md="4">
                    <v-card variant="tonal">
                        <v-card-title class="text-subtitle-2">Tracked Time</v-card-title>
                        <v-card-text class="text-h6">{{ formatDuration(summary?.trackedSeconds || 0) }}</v-card-text>
                    </v-card>
                </v-col>

                <v-col cols="12" md="4">
                    <v-card variant="tonal">
                        <v-card-title class="text-subtitle-2">Active</v-card-title>
                        <v-card-text class="text-h6">{{ formatDuration(summary?.activeSeconds || 0) }}</v-card-text>
                    </v-card>
                </v-col>

                <v-col cols="12" md="4">
                    <v-card variant="tonal">
                        <v-card-title class="text-subtitle-2">Idle</v-card-title>
                        <v-card-text class="text-h6">{{ formatDuration(summary?.idleSeconds || 0) }}</v-card-text>
                    </v-card>
                </v-col>
            </v-row>

            <div v-if="timelineRows.length">
                <div v-for="row in timelineRows" :key="row.hour" class="timeline-row">
                    <div class="hour-label">{{ row.hourLabel }}</div>

                    <div class="hour-slots">
                        <div
                            v-for="slot in row.slots"
                            :key="slot.startTime"
                            class="slot-card"
                            :title="slotTitle(slot)"
                            :class="{ 'empty-slot': slot.empty }"
                            @click="!slot.empty && openSlot(slot)"
                        >
                            <div class="slot-time">{{ formatRange(slot.startTime, slot.endTime) }}</div>

                            <div class="minute-track">
                                <span class="minute" :class="slot.idleSeconds > slot.activeSeconds ? 'idle' : 'active'" />
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </v-card-text>
    </v-card>

    <v-dialog v-model="slotDialog" max-width="1000">
        <v-card>
            <v-card-title class="d-flex align-center ga-2">
                <span>Activity Details · {{ formatRange(selectedSlot?.startTime, selectedSlot?.endTime) }}</span>
                <v-spacer />
                <v-btn icon="mdi-close" variant="text" @click="slotDialog=false" />
            </v-card-title>

            <v-card-text>
                <v-row class="mb-3">
                    <v-col cols="12" md="3"><strong>Tracked</strong><br>{{ formatDuration(selectedSlot?.trackedSeconds || 0) }}</v-col>
                    <v-col cols="12" md="3"><strong>Active</strong><br>{{ formatDuration(selectedSlot?.activeSeconds || 0) }}</v-col>
                    <v-col cols="12" md="3"><strong>Idle</strong><br>{{ formatDuration(selectedSlot?.idleSeconds || 0) }}</v-col>
                    <v-col cols="12" md="3"><strong>Keyboard</strong><br>{{ selectedSlot?.keyboardCount || 0 }}</v-col>
                    <v-col cols="12" md="3"><strong>Mouse</strong><br>{{ selectedSlot?.mouseCount || 0 }}</v-col>
                    <v-col cols="12" md="3"><strong>Apps</strong><br>{{ slotApplications }}</v-col>
                </v-row>

                <v-data-table :headers="minuteHeaders" :items="slotActivities" density="compact" />
            </v-card-text>
        </v-card>
    </v-dialog>
</template>

<script setup>
import axios from "axios"
import { ref, computed, onMounted, watch } from "vue"
import { useRoute, useRouter } from "vue-router"
import { currentUser } from "../auth"
import { apiEndpoints } from "../apiEndpoints"

const route = useRoute()
const router = useRouter()

const selectedDate = ref(typeof route.query.date === "string" ? route.query.date : formatAsYmd(new Date()))
const selectedUserId = ref(route.query.user ? Number(route.query.user) : null)
const memberSearch = ref("")
const dateMenu = ref(false)

const organization = ref(null)
const userOptions = ref([])
const membersLoading = ref(false)

const activities = ref([])
const slots = ref([])
const summary = ref(null)

const selectedSlot = ref(null)
const slotDialog = ref(false)

const minuteHeaders = [
    { title: "Time", key: "time" },
    { title: "Keyboard", key: "keyboard" },
    { title: "Mouse", key: "mouse" },
    { title: "Activity", key: "activity" },
    { title: "Apps", key: "apps" }
]

const canViewAllTracking = computed(() =>
    Boolean(organization.value?.isAdmin)
    || Boolean(organization.value?.isManager)
)
const formattedDate = computed(() => {
    const parsed = parseDateInput(selectedDate.value)
    return parsed
        ? parsed.toLocaleDateString("en-IN", { day: "2-digit", month: "short", year: "numeric" })
        : ""
})

const timelineRows = computed(() => {
    const rows = {}

    // Step 1: Create lookup for API slots
    const slotMap = {}
    for (const slot of slots.value) {
        const key = new Date(slot.startTime).getTime()
        slotMap[key] = slot
    }

    // Step 2: Build full day (24 hours × 6 slots)
    const baseDate = parseDateInput(selectedDate.value) || new Date()

    for (let hour = 0; hour < 24; hour++) {
        const rowSlots = []

        for (let i = 0; i < 6; i++) {
            const start = new Date(baseDate)
            start.setHours(hour, i * 10, 0, 0)

            const end = new Date(start.getTime() + 10 * 60 * 1000)
            const key = start.getTime()

            const existing = slotMap[key]

            rowSlots.push(
                existing || {
                    startTime: start.toISOString(),
                    endTime: end.toISOString(),
                    trackedSeconds: 0,
                    activeSeconds: 0,
                    idleSeconds: 0,
                    keyboardCount: 0,
                    mouseCount: 0,
                    applications: {},
                    empty: true
                }
            )
        }

        rows[hour] = {
            hour,
            hourLabel: hourRangeLabel(hour),
            slots: rowSlots
        }
    }

    return Object.values(rows)
})

function openSlot(slot) {
    selectedSlot.value = slot
    slotDialog.value = true
}

const slotApplications = computed(() => {
    if (!selectedSlot.value?.applications) return "-"

    return Object.entries(selectedSlot.value.applications)
        .sort((a, b) => b[1] - a[1])
        .slice(0, 3)
        .map(([name]) => name)
        .join(", ")
})

const slotActivities = computed(() => {
    if (!selectedSlot.value) return []

    const start = new Date(selectedSlot.value.startTime).getTime()
    const end = new Date(selectedSlot.value.endTime).getTime()

    return activities.value
        .filter(item => {
            const s = new Date(item.startTime).getTime()
            const e = s + (item.durationSeconds * 1000)
            return s < end && e > start
        })
        .map(item => ({
            time: formatRange(item.startTime, new Date(new Date(item.startTime).getTime() + item.durationSeconds * 1000)),
            keyboard: item.keyboardCount,
            mouse: item.mouseCount,
            activity: item.activityPercent + "%",
            apps: Object.keys(item.applications || {}).join(", ")
        }))
})

function parseDateInput(date) {
    if (!date) return null

    if (date instanceof Date) {
        return Number.isNaN(date.getTime()) ? null : new Date(date.getFullYear(), date.getMonth(), date.getDate())
    }

    if (typeof date === "string" && /^\d{4}-\d{2}-\d{2}$/.test(date)) {
        const [year, month, day] = date.split("-").map(Number)
        const parsed = new Date(year, month - 1, day)
        return Number.isNaN(parsed.getTime()) ? null : parsed
    }

    const parsed = new Date(date)
    return Number.isNaN(parsed.getTime()) ? null : new Date(parsed.getFullYear(), parsed.getMonth(), parsed.getDate())
}

function formatAsYmd(date) {
    const year = date.getFullYear()
    const month = `${date.getMonth() + 1}`.padStart(2, "0")
    const day = `${date.getDate()}`.padStart(2, "0")
    return `${year}-${month}-${day}`
}

function normalizeDateValue(value) {
    const parsed = parseDateInput(value)
    return parsed ? formatAsYmd(parsed) : formatAsYmd(new Date())
}

function formatDuration(seconds) {
    seconds = Math.round(Number(seconds) || 0)
    const totalMinutes = Math.round(seconds / 60)
    const h = Math.floor(totalMinutes / 60)
    const m = totalMinutes % 60
    return `${h}h ${m}m`
}

function formatTimestamp(sec) {
    return new Intl.DateTimeFormat(undefined, { hour: "numeric", minute: "2-digit" }).format(new Date(sec * 1000))
}

function formatRange(start, end) {
    return `${formatTimestamp(new Date(start).getTime() / 1000)} - ${formatTimestamp(new Date(end).getTime() / 1000)}`
}

function hourRangeLabel(hour) {
    const start = new Date()
    start.setHours(hour, 0, 0)

    const end = new Date()
    end.setHours(hour + 1, 0, 0)

    const f = new Intl.DateTimeFormat(undefined, { hour: "numeric", minute: "2-digit" })
    return `${f.format(start)} - ${f.format(end)}`
}

function slotTitle(slot) {
    return `Tracked: ${Math.round(slot.trackedSeconds / 60)}m • Active: ${Math.round(slot.activeSeconds / 60)}m • Idle: ${Math.round(slot.idleSeconds / 60)}m`
}

async function bootstrapScope() {
    const { data } = await axios.get(apiEndpoints.organizations.list, { params: { page: 1, perPage: 1 } })
    organization.value = data?.data?.[0] || null

    await fetchMembers(memberSearch.value)

    if (!selectedUserId.value && userOptions.value.length) {
        selectedUserId.value = userOptions.value[0].id
    }
}

async function fetchMembers(search = "") {
    if (!organization.value?.id) return

    membersLoading.value = true
    try {
        const { data } = await axios.get(apiEndpoints.organizations.members(organization.value.id), {
            params: {
                page: 1,
                perPage: 20,
                search: search || undefined
            }
        })

        userOptions.value = (data?.data || []).map((member) => ({
            id: Number(member.id),
            label: member.displayName || member.email || `User ${member.id}`
        }))
    } finally {
        membersLoading.value = false
    }
}
async function fetchActivities() {
    if (!selectedUserId.value) return

    try {
        const params = {
            date: normalizeDateValue(selectedDate.value)
        }

        // ONLY send limit if NO date filter (future-proof)
        if (!params.date) {
            params.limit = 100
        }

        const { data } = await axios.get(
            apiEndpoints.users.activities(selectedUserId.value),
            { params }
        )

        const { items = [], slots: apiSlots = [], summary: apiSummary = null } = data.data
        activities.value = items
        slots.value = apiSlots
        summary.value = apiSummary

        slotDialog.value = false
        selectedSlot.value = null
    } catch (error) {
        console.error(error)
    }
}

watch(memberSearch, async (value) => {
    if (!canViewAllTracking.value) return
    await fetchMembers(typeof value === "string" ? value.trim() : "")
})

watch([selectedDate, selectedUserId], async () => {
    const normalizedDate = normalizeDateValue(selectedDate.value)
    if (selectedDate.value !== normalizedDate) {
        selectedDate.value = normalizedDate
        return
    }

    router.replace({
        query: {
            date: normalizedDate,
            user: selectedUserId.value || undefined
        }
    })

    await fetchActivities()
})

onMounted(async () => {
    await bootstrapScope()
    await fetchActivities()
})
</script>

<style scoped>
.timeline-row {
    display: flex;
    gap: 10px;
    margin-bottom: 10px;
}

.hour-label {
    width: 140px;
    font-size: 12px;
    color: #455a64;
    padding-top: 8px;
}

.hour-slots {
    flex: 1;
    display: grid;
    grid-template-columns: repeat(6, minmax(130px, 1fr));
    gap: 6px;
}

.slot-card {
    border: 1px solid #d9e2e6;
    border-radius: 6px;
    padding: 6px;
    background: #fafbfc;
    cursor: pointer;
}

.slot-time {
    font-size: 11px;
    color: #607d8b;
    margin-bottom: 4px;
}

.minute-track {
    display: grid;
    grid-template-columns: 1fr;
}

.minute {
    height: 10px;
    border-radius: 2px;
    background: #eceff1;
}

.minute.active {
    background: #4caf50;
}

.minute.idle {
    background: #ff9800;
}
.empty-slot {
    background: #f5f5f5;
    border-style: dashed;
    cursor: default;
    opacity: 0.6;
}

.empty-slot .minute {
    background: transparent;
}
</style>
