<template>
  <div class="p-6">
    <div class="flex items-center justify-between mb-6">
      <h1 class="text-[1.75rem] font-bold font-[family-name:var(--font-heading)] tracking-tight text-text-primary">Timesheet</h1>

      <!-- Week Navigation -->
      <div class="flex items-center gap-3">
        <button
          @click="prevWeek"
          v-tooltip="'Previous week'"
          class="p-1.5 rounded-lg text-text-tertiary hover:text-text-secondary hover:bg-bg-elevated transition-colors duration-150"
          aria-label="Previous week"
        >
          <ChevronLeft class="w-4 h-4" :stroke-width="2" aria-hidden="true" />
        </button>

        <button
          @click="goToThisWeek"
          class="px-3 py-1.5 text-xs text-text-secondary border border-border-subtle rounded-lg hover:text-text-primary hover:bg-bg-elevated transition-colors duration-150 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent"
        >
          This Week
        </button>

        <button
          @click="copyLastWeekStructure"
          :disabled="isCurrentWeekLocked"
          class="px-3 py-1.5 text-xs text-text-secondary border border-border-subtle rounded-lg hover:text-text-primary hover:bg-bg-elevated transition-colors duration-150 disabled:opacity-40 disabled:cursor-not-allowed focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent"
        >
          Copy Last Week
        </button>

        <button
          @click="nextWeek"
          v-tooltip="'Next week'"
          class="p-1.5 rounded-lg text-text-tertiary hover:text-text-secondary hover:bg-bg-elevated transition-colors duration-150"
          aria-label="Next week"
        >
          <ChevronRight class="w-4 h-4" :stroke-width="2" aria-hidden="true" />
        </button>

        <span class="text-[0.75rem] text-text-secondary font-medium ml-2" role="status" aria-live="polite">
          {{ weekRangeLabel }}
        </span>

        <!-- Lock status + button -->
        <template v-if="isCurrentWeekLocked">
          <span class="flex items-center gap-1 text-[0.6875rem] text-amber-500 ml-3">
            <Lock class="w-3.5 h-3.5" :stroke-width="2" aria-hidden="true" />
            Locked
          </span>
          <button
            @click="showUnlockConfirm = true"
            class="ml-1 px-2.5 py-1 text-[0.6875rem] text-text-secondary border border-border-subtle rounded-lg hover:text-text-primary hover:bg-bg-elevated transition-colors duration-150"
          >
            Unlock
          </button>
        </template>
        <template v-else-if="canLock">
          <button
            @click="showLockConfirm = true"
            class="ml-3 flex items-center gap-1 px-2.5 py-1 text-[0.6875rem] text-text-secondary border border-border-subtle rounded-lg hover:text-text-primary hover:bg-bg-elevated transition-colors duration-150"
          >
            <Lock class="w-3.5 h-3.5" :stroke-width="2" aria-hidden="true" />
            Lock Week
          </button>
        </template>
      </div>
    </div>

    <!-- Timesheet Table -->
    <Transition name="fade" mode="out-in">
    <div :key="weekStart" class="bg-bg-surface rounded-lg overflow-hidden">
      <table class="w-full">
        <thead>
          <tr class="border-b border-border-subtle bg-bg-surface">
            <th class="px-4 py-3 text-left text-[0.6875rem] text-text-tertiary uppercase tracking-[0.08em] font-medium w-56">
              <span class="flex items-center gap-1.5">
                Project / Task
                <Lock v-if="isCurrentWeekLocked" class="w-3 h-3 text-amber-500" :stroke-width="2" aria-label="Week is locked" />
              </span>
            </th>
            <th
              v-for="(day, i) in dayHeaders"
              :key="i"
              class="px-4 py-3 text-right text-[0.6875rem] text-text-tertiary uppercase tracking-[0.08em] font-medium"
              :class="{ 'text-text-secondary': isToday(i) }"
            >
              {{ day }}
            </th>
            <th class="px-4 py-3 text-right text-[0.6875rem] text-text-tertiary uppercase tracking-[0.08em] font-medium">
              Total
            </th>
          </tr>
        </thead>
        <tbody>
          <!-- Data rows -->
          <tr
            v-for="(row, rowIndex) in rows"
            :key="rowIndex"
            class="border-b border-border-subtle transition-colors duration-150"
            :class="isCurrentWeekLocked ? 'bg-bg-inset' : 'hover:bg-bg-elevated'"
            :aria-label="isCurrentWeekLocked ? 'This week is locked' : undefined"
          >
            <td class="px-4 py-3">
              <div class="flex items-center gap-2">
                <div
                  class="w-2 h-2 rounded-full shrink-0"
                  :style="{ backgroundColor: row.color }"
                  aria-hidden="true"
                />
                <span class="text-[0.75rem] text-text-primary truncate">{{ row.project_name }}</span>
                <span v-if="row.task_name" class="text-[0.75rem] text-text-tertiary truncate">/ {{ row.task_name }}</span>
              </div>
            </td>
            <td
              v-for="(seconds, dayIndex) in row.days"
              :key="dayIndex"
              @click="startEdit(rowIndex, dayIndex)"
              @keydown.enter="startEdit(rowIndex, dayIndex)"
              tabindex="0"
              role="gridcell"
              :aria-label="'Hours for ' + row.project_name + ' on ' + getDayLabel(dayIndex) + ': ' + formatHM(seconds)"
              class="px-4 py-3 text-right text-[0.75rem] font-mono transition-colors duration-150"
              :class="[
                seconds > 0 ? 'text-accent-text' : 'text-text-tertiary',
                !isCurrentWeekLocked ? 'cursor-pointer hover:bg-bg-elevated' : ''
              ]"
            >
              <template v-if="editingCell?.rowIdx === rowIndex && editingCell?.dayIdx === dayIndex">
                <input
                  ref="editInputRef"
                  v-model="editValue"
                  @blur="saveEdit()"
                  @keydown.enter.prevent="saveEdit()"
                  @keydown.escape.prevent="cancelEdit()"
                  @keydown.tab="saveEdit()"
                  class="w-full text-right text-[0.75rem] font-mono bg-transparent border-b-2 border-accent outline-none text-text-primary"
                  aria-label="Enter hours (decimal or H:MM)"
                />
              </template>
              <template v-else>
                {{ formatHM(seconds) }}
              </template>
            </td>
            <td class="px-4 py-3 text-right text-[0.75rem] font-mono text-accent-text font-medium">
              {{ formatHM(rowTotal(row)) }}
            </td>
          </tr>

          <!-- Add Row (inline) -->
          <tr v-if="showAddRow" class="border-b border-border-subtle bg-bg-inset">
            <td class="px-4 py-3" colspan="9">
              <div class="flex items-center gap-3">
                <div class="w-48">
                  <AppSelect
                    v-model="newRowProjectId"
                    :options="availableProjects"
                    label-key="name"
                    value-key="id"
                    placeholder="Select project"
                    :placeholder-value="null"
                    :searchable="true"
                    aria-label="Select project"
                  />
                </div>
                <div class="w-48">
                  <AppSelect
                    v-model="newRowTaskId"
                    :options="availableTasks"
                    label-key="name"
                    value-key="id"
                    placeholder="No task"
                    :placeholder-value="null"
                    :searchable="true"
                    :disabled="!newRowProjectId"
                    aria-label="Select task"
                  />
                </div>
                <button
                  @click="confirmAddRow"
                  :disabled="!newRowProjectId"
                  class="px-3 py-1.5 bg-accent text-bg-base text-xs font-medium rounded-lg hover:bg-accent-hover transition-colors duration-150 disabled:opacity-40 disabled:cursor-not-allowed"
                >
                  Add
                </button>
                <button
                  @click="cancelAddRow"
                  class="px-3 py-1.5 text-text-secondary text-xs hover:text-text-primary transition-colors duration-150"
                >
                  Cancel
                </button>
              </div>
            </td>
          </tr>

          <!-- Empty state -->
          <tr v-if="rows.length === 0 && !showAddRow">
            <td colspan="9" class="px-4 py-12">
              <div class="flex flex-col items-center justify-center">
                <ClockIcon class="w-12 h-12 text-text-tertiary animate-float" :stroke-width="1.5" aria-hidden="true" />
                <p class="text-sm text-text-secondary mt-4">No timesheet data for this week</p>
                <p class="text-xs text-text-tertiary mt-2">Start tracking time to see your weekly timesheet.</p>
                <router-link to="/timer" class="mt-4 px-4 py-2 bg-accent text-bg-base text-xs font-medium rounded-lg hover:bg-accent-hover transition-colors">
                  Go to Timer
                </router-link>
                <button
                  v-if="onboardingStore.isVisible"
                  @click="tourStore.start(TOURS.timer)"
                  class="mt-2 text-[0.6875rem] text-accent-text hover:underline"
                >
                  Show me how
                </button>
              </div>
            </td>
          </tr>
        </tbody>
        <tfoot>
          <!-- Column totals -->
          <tr class="border-t border-border-visible bg-bg-elevated">
            <td class="px-4 py-3 text-[0.6875rem] text-text-secondary uppercase tracking-[0.08em] font-medium">
              Total
            </td>
            <td
              v-for="(total, i) in columnTotals"
              :key="i"
              class="px-4 py-3 text-right text-[0.75rem] font-mono text-text-primary font-medium"
            >
              {{ formatHM(total) }}
            </td>
            <td class="px-4 py-3 text-right text-[0.75rem] font-mono text-accent-text font-bold">
              {{ formatHM(grandTotal) }}
            </td>
          </tr>
        </tfoot>
      </table>
    </div>
    </Transition>

    <!-- Add Row Button -->
    <button
      v-if="!showAddRow"
      @click="startAddRow"
      :disabled="isCurrentWeekLocked"
      class="mt-3 flex items-center gap-1.5 text-text-secondary text-xs hover:text-text-primary transition-colors duration-150 disabled:opacity-40 disabled:cursor-not-allowed"
      :aria-label="isCurrentWeekLocked ? 'Cannot add rows to a locked week' : 'Add row'"
    >
      <Plus class="w-4 h-4" :stroke-width="2" aria-hidden="true" />
      Add Row
    </button>

    <!-- Lock Confirmation Dialog -->
    <Transition name="modal">
    <div
      v-if="showLockConfirm"
      class="fixed inset-0 bg-black/70 backdrop-blur-[4px] flex items-center justify-center p-4 z-50"
      @click.self="showLockConfirm = false"
    >
      <div class="bg-bg-surface border border-border-subtle rounded-lg shadow-[0_1px_3px_rgba(0,0,0,0.3)] w-full max-w-sm p-6" role="alertdialog" aria-modal="true" aria-labelledby="lock-title" aria-describedby="lock-desc">
        <h2 id="lock-title" class="text-[1.125rem] font-semibold font-[family-name:var(--font-heading)] text-text-primary mb-2">Lock Week</h2>
        <p id="lock-desc" class="text-[0.75rem] text-text-secondary mb-6">
          Locking this week will prevent any changes to time entries within it. You can unlock it later if needed.
        </p>
        <div class="flex justify-end gap-3">
          <button
            @click="showLockConfirm = false"
            class="px-4 py-2 border border-border-subtle text-text-secondary rounded-lg hover:bg-bg-elevated transition-colors duration-150"
          >
            Cancel
          </button>
          <button
            @click="lockWeek"
            class="px-4 py-2 bg-accent text-bg-base font-medium rounded-lg hover:bg-accent-hover transition-colors duration-150"
          >
            Lock
          </button>
        </div>
      </div>
    </div>
    </Transition>

    <!-- Unlock Confirmation Dialog -->
    <Transition name="modal">
    <div
      v-if="showUnlockConfirm"
      class="fixed inset-0 bg-black/70 backdrop-blur-[4px] flex items-center justify-center p-4 z-50"
      @click.self="showUnlockConfirm = false"
    >
      <div class="bg-bg-surface border border-border-subtle rounded-lg shadow-[0_1px_3px_rgba(0,0,0,0.3)] w-full max-w-sm p-6" role="alertdialog" aria-modal="true" aria-labelledby="unlock-title" aria-describedby="unlock-desc">
        <h2 id="unlock-title" class="text-[1.125rem] font-semibold font-[family-name:var(--font-heading)] text-text-primary mb-2">Unlock Week</h2>
        <p id="unlock-desc" class="text-[0.75rem] text-text-secondary mb-6">
          Unlocking this week will allow changes to time entries. Are you sure?
        </p>
        <div class="flex justify-end gap-3">
          <button
            @click="showUnlockConfirm = false"
            class="px-4 py-2 border border-border-subtle text-text-secondary rounded-lg hover:bg-bg-elevated transition-colors duration-150"
          >
            Cancel
          </button>
          <button
            @click="unlockWeek"
            class="px-4 py-2 border border-status-error text-status-error-text font-medium rounded-lg hover:bg-status-error/10 transition-colors duration-150"
          >
            Unlock
          </button>
        </div>
      </div>
    </div>
    </Transition>

    <div class="sr-only" aria-live="polite" aria-atomic="true">{{ liveAnnouncement }}</div>
  </div>
</template>

<script setup lang="ts">
import { ref, computed, watch, onMounted, nextTick } from 'vue'
import { ChevronLeft, ChevronRight, Plus, Lock, Clock as ClockIcon } from 'lucide-vue-next'
import { invoke } from '@tauri-apps/api/core'
import AppSelect from '../components/AppSelect.vue'
import { useProjectsStore, type Task } from '../stores/projects'
import { useToastStore } from '../stores/toast'
import { useOnboardingStore } from '../stores/onboarding'
import { useTourStore } from '../stores/tour'
import { TOURS } from '../utils/tours'

const projectsStore = useProjectsStore()
const toast = useToastStore()
const onboardingStore = useOnboardingStore()
const tourStore = useTourStore()

// ── Types ──────────────────────────────────────────────────────────────

interface TimesheetRow {
  project_id: number
  project_name: string
  color: string
  task_id: number | null
  task_name: string | null
  days: number[] // 7 elements, Mon-Sun, in seconds
}

// ── Week state ─────────────────────────────────────────────────────────

/** The Monday of the currently displayed week (YYYY-MM-DD) */
const weekStart = ref('')

function getMonday(d: Date): Date {
  const date = new Date(d)
  const day = date.getDay()
  // getDay(): 0=Sun, 1=Mon … 6=Sat → offset to Monday
  const diff = day === 0 ? -6 : 1 - day
  date.setDate(date.getDate() + diff)
  date.setHours(0, 0, 0, 0)
  return date
}

function formatISODate(d: Date): string {
  const y = d.getFullYear()
  const m = String(d.getMonth() + 1).padStart(2, '0')
  const day = String(d.getDate()).padStart(2, '0')
  return `${y}-${m}-${day}`
}

function goToThisWeek() {
  weekStart.value = formatISODate(getMonday(new Date()))
}

function prevWeek() {
  const d = new Date(weekStart.value)
  d.setDate(d.getDate() - 7)
  weekStart.value = formatISODate(d)
}

function nextWeek() {
  const d = new Date(weekStart.value)
  d.setDate(d.getDate() + 7)
  weekStart.value = formatISODate(d)
}

// ── Computed labels ────────────────────────────────────────────────────

const weekDates = computed(() => {
  const start = new Date(weekStart.value)
  return Array.from({ length: 7 }, (_, i) => {
    const d = new Date(start)
    d.setDate(start.getDate() + i)
    return d
  })
})

const shortDayNames = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']

const shortMonthNames = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']

const dayHeaders = computed(() =>
  weekDates.value.map((d, i) => `${shortDayNames[i]} ${d.getDate()}`)
)

const weekRangeLabel = computed(() => {
  if (weekDates.value.length === 0) return ''
  const first = weekDates.value[0]
  const last = weekDates.value[6]

  const fMonth = shortMonthNames[first.getMonth()]
  const lMonth = shortMonthNames[last.getMonth()]
  const fDay = first.getDate()
  const lDay = last.getDate()
  const year = last.getFullYear()

  if (fMonth === lMonth) {
    return `${fMonth} ${fDay} - ${lDay}, ${year}`
  }
  return `${fMonth} ${fDay} - ${lMonth} ${lDay}, ${year}`
})

function isToday(dayIndex: number): boolean {
  const d = weekDates.value[dayIndex]
  if (!d) return false
  const today = new Date()
  return (
    d.getFullYear() === today.getFullYear() &&
    d.getMonth() === today.getMonth() &&
    d.getDate() === today.getDate()
  )
}

// ── Timesheet data ─────────────────────────────────────────────────────

const rows = ref<TimesheetRow[]>([])
const loading = ref(false)

async function fetchTimesheetData() {
  loading.value = true
  try {
    const data = await invoke<TimesheetRow[]>('get_timesheet_data', {
      weekStart: weekStart.value,
    })
    rows.value = data
  } catch (error) {
    console.error('Failed to fetch timesheet data:', error)
    rows.value = []
  } finally {
    loading.value = false
  }
}

// Persist current row structure to backend
async function persistRows() {
  try {
    const rowData = rows.value.map((r, i) => ({
      project_id: r.project_id,
      task_id: r.task_id,
      sort_order: i,
    }))
    await invoke('save_timesheet_rows', { weekStart: weekStart.value, rows: rowData })
  } catch {
    // Silent failure - row persistence is a convenience feature
  }
}

// Load previous week's row structure if current week has no rows
async function maybeLoadPreviousStructure() {
  if (rows.value.length > 0) return
  try {
    const prevRows = await invoke<any[]>('get_previous_week_structure', { currentWeekStart: weekStart.value })
    if (prevRows.length > 0) {
      for (const pr of prevRows) {
        const project = projectsStore.projects.find(p => p.id === pr.project_id)
        if (!project) continue
        let taskName: string | null = null
        if (pr.task_id) {
          const tasks = await projectsStore.fetchTasks(pr.project_id)
          taskName = tasks.find(t => t.id === pr.task_id)?.name ?? null
        }
        rows.value.push({
          project_id: pr.project_id,
          project_name: project.name,
          color: project.color,
          task_id: pr.task_id || null,
          task_name: taskName,
          days: [0, 0, 0, 0, 0, 0, 0],
        })
      }
    }
  } catch {
    // No previous structure
  }
}

// Copy previous week's row structure into current week
async function copyLastWeekStructure() {
  try {
    const prevRows = await invoke<any[]>('get_previous_week_structure', { currentWeekStart: weekStart.value })
    if (prevRows.length === 0) {
      toast.info('No rows found in previous week')
      return
    }
    for (const pr of prevRows) {
      const project = projectsStore.projects.find(p => p.id === pr.project_id)
      if (!project) continue
      // Skip if already exists
      const exists = rows.value.some(
        r => r.project_id === pr.project_id && r.task_id === (pr.task_id || null)
      )
      if (exists) continue
      let taskName: string | null = null
      if (pr.task_id) {
        const tasks = await projectsStore.fetchTasks(pr.project_id)
        taskName = tasks.find(t => t.id === pr.task_id)?.name ?? null
      }
      rows.value.push({
        project_id: pr.project_id,
        project_name: project.name,
        color: project.color,
        task_id: pr.task_id || null,
        task_name: taskName,
        days: [0, 0, 0, 0, 0, 0, 0],
      })
    }
    await persistRows()
    toast.success('Copied row structure from last week')
  } catch {
    toast.error('Failed to copy last week structure')
  }
}

// Re-fetch whenever weekStart changes
watch(weekStart, async () => {
  await fetchTimesheetData()
  await maybeLoadPreviousStructure()
})

// ── Totals ─────────────────────────────────────────────────────────────

function rowTotal(row: TimesheetRow): number {
  return row.days.reduce((sum, s) => sum + s, 0)
}

const columnTotals = computed(() => {
  const totals = [0, 0, 0, 0, 0, 0, 0]
  for (const row of rows.value) {
    for (let i = 0; i < 7; i++) {
      totals[i] += row.days[i] ?? 0
    }
  }
  return totals
})

const grandTotal = computed(() =>
  columnTotals.value.reduce((sum, s) => sum + s, 0)
)

// ── Formatting ─────────────────────────────────────────────────────────

function formatHM(seconds: number): string {
  if (seconds === 0) return '-'
  const h = Math.floor(seconds / 3600)
  const m = Math.floor((seconds % 3600) / 60)
  return `${h}:${String(m).padStart(2, '0')}`
}

// ── Inline Editing ──────────────────────────────────────────────────────

const editingCell = ref<{ rowIdx: number; dayIdx: number } | null>(null)
const editValue = ref('')
const editInputRef = ref<HTMLInputElement | null>(null)
const liveAnnouncement = ref('')

function startEdit(rowIdx: number, dayIdx: number) {
  if (isCurrentWeekLocked.value) return
  const row = rows.value[rowIdx]
  if (!row) return
  editingCell.value = { rowIdx, dayIdx }
  const seconds = row.days[dayIdx]
  editValue.value = seconds > 0 ? formatHoursDecimal(seconds) : ''
  nextTick(() => {
    editInputRef.value?.focus()
    editInputRef.value?.select()
  })
}

function cancelEdit() {
  editingCell.value = null
  editValue.value = ''
}

function formatHoursDecimal(seconds: number): string {
  return (seconds / 3600).toFixed(2)
}

function parseTimeInput(input: string): number | null {
  const trimmed = input.trim()
  if (!trimmed) return 0

  if (trimmed.includes(':')) {
    const [h, m] = trimmed.split(':').map(Number)
    if (isNaN(h) || isNaN(m) || h < 0 || m < 0 || m > 59) return null
    const seconds = h * 3600 + m * 60
    if (seconds > 86400) return null
    return seconds
  }

  const num = parseFloat(trimmed)
  if (isNaN(num) || num < 0 || num > 24) return null
  return Math.round(num * 3600)
}

function getDayDate(dayIdx: number): string {
  const dates = weekDates.value
  if (dates[dayIdx]) return formatISODate(dates[dayIdx])
  return ''
}

function getDayLabel(dayIdx: number): string {
  const labels = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']
  return labels[dayIdx] || ''
}

async function saveEdit() {
  if (!editingCell.value) return
  const { rowIdx, dayIdx } = editingCell.value
  const row = rows.value[rowIdx]
  if (!row) { cancelEdit(); return }

  const seconds = parseTimeInput(editValue.value)
  if (seconds === null) { cancelEdit(); return }

  const date = getDayDate(dayIdx)
  if (!date) { cancelEdit(); return }

  try {
    await invoke('upsert_timesheet_entry', {
      projectId: row.project_id,
      taskId: row.task_id,
      date,
      durationSeconds: seconds,
    })
    row.days[dayIdx] = seconds
    liveAnnouncement.value = `Saved ${formatHoursDecimal(seconds)} hours for ${row.project_name} on ${getDayLabel(dayIdx)}`
  } catch (e) {
    console.error('Failed to save timesheet entry:', e)
    toast.error('Failed to save entry')
  }
  cancelEdit()
}

// ── Add Row ────────────────────────────────────────────────────────────

const showAddRow = ref(false)
const newRowProjectId = ref<number | null>(null)
const newRowTaskId = ref<number | null>(null)
const availableTasks = ref<Task[]>([])

const availableProjects = computed(() =>
  projectsStore.projects.filter((p) => !p.archived)
)

// When selected project changes, fetch its tasks
watch(newRowProjectId, async (projectId) => {
  newRowTaskId.value = null
  if (projectId) {
    availableTasks.value = await projectsStore.fetchTasks(projectId)
  } else {
    availableTasks.value = []
  }
})

function startAddRow() {
  showAddRow.value = true
  newRowProjectId.value = null
  newRowTaskId.value = null
  availableTasks.value = []
}

function cancelAddRow() {
  showAddRow.value = false
  newRowProjectId.value = null
  newRowTaskId.value = null
}

function confirmAddRow() {
  if (!newRowProjectId.value) return

  const project = projectsStore.projects.find(
    (p) => p.id === newRowProjectId.value
  )
  if (!project) return

  // Check if this project+task combo already exists
  const exists = rows.value.some(
    (r) =>
      r.project_id === newRowProjectId.value &&
      r.task_id === (newRowTaskId.value ?? null)
  )
  if (exists) {
    cancelAddRow()
    return
  }

  const taskName =
    newRowTaskId.value
      ? availableTasks.value.find((t) => t.id === newRowTaskId.value)?.name ?? null
      : null

  rows.value.push({
    project_id: project.id!,
    project_name: project.name,
    color: project.color,
    task_id: newRowTaskId.value,
    task_name: taskName,
    days: [0, 0, 0, 0, 0, 0, 0],
  })

  persistRows()
  cancelAddRow()
}

// ── Timesheet locks ───────────────────────────────────────────────────

interface TimesheetLock {
  id: number
  week_start: string
  status: string
  locked_at: string
}

const lockedWeeks = ref<Set<string>>(new Set())
const showLockConfirm = ref(false)
const showUnlockConfirm = ref(false)

const isCurrentWeekLocked = computed(() => lockedWeeks.value.has(weekStart.value))

const isPastWeek = computed(() => {
  const currentMonday = formatISODate(getMonday(new Date()))
  return weekStart.value < currentMonday
})

const canLock = computed(() => isPastWeek.value && !isCurrentWeekLocked.value)

async function fetchLocks() {
  try {
    const locks = await invoke<TimesheetLock[]>('get_timesheet_locks')
    lockedWeeks.value = new Set(locks.map(l => l.week_start))
  } catch (error) {
    console.error('Failed to fetch locks:', error)
  }
}

async function lockWeek() {
  try {
    await invoke('lock_timesheet_week', { weekStart: weekStart.value })
    lockedWeeks.value.add(weekStart.value)
    toast.success('Week locked')
  } catch (error) {
    toast.error('Failed to lock week')
  }
  showLockConfirm.value = false
}

async function unlockWeek() {
  try {
    await invoke('unlock_timesheet_week', { weekStart: weekStart.value })
    lockedWeeks.value.delete(weekStart.value)
    toast.success('Week unlocked')
  } catch (error) {
    toast.error('Failed to unlock week')
  }
  showUnlockConfirm.value = false
}

// ── Init ───────────────────────────────────────────────────────────────

onMounted(async () => {
  await projectsStore.fetchProjects()
  goToThisWeek() // triggers watch -> fetchTimesheetData
  fetchLocks()
})
</script>
