<script>
  import { liveQuery } from 'dexie'
  import { db } from '../db.js'
  import { api } from '../api.js'

  let { session } = $props()

  let error = $state('')
  let editShiftID = $state(null)
  let editShift = $state({})
  let saving = $state(false)

  // For volunteer assignment dropdown
  let assigningShiftID = $state(null)
  let assignVolID = $state(0)
  let assigning = $state(false)

  const role = $derived(session?.user?.role ?? '')
  const myDeptIDs = $derived(session?.user?.department_ids ?? [])

  const allDepts = liveQuery(() =>
    db.departments.filter(d => !d.deleted_at).toArray()
      .then(arr => arr.sort((a, b) => a.name.localeCompare(b.name)))
  )

  const allShifts = liveQuery(() =>
    db.shifts.filter(s => !s.deleted_at).toArray()
      .then(arr => arr.sort((a, b) =>
        (a.day === b.day ? (a.position - b.position || a.start_time.localeCompare(b.start_time))
          : a.day.localeCompare(b.day))
      ))
  )

  const allVolunteers = liveQuery(() =>
    db.volunteers.filter(v => !v.deleted_at).toArray()
      .then(arr => arr.sort((a, b) => a.name.localeCompare(b.name)))
  )

  const allVolunteerShifts = liveQuery(() =>
    db.volunteer_shifts.toArray()
  )

  // Departments visible to this user
  const visibleDepts = $derived.by(() => {
    const depts = $allDepts ?? []
    if (role === 'volunteer_lead') return depts.filter(d => myDeptIDs.includes(d.id))
    return depts
  })

  // Grouped structure: dept → days → shifts
  const board = $derived.by(() => {
    const shifts = $allShifts ?? []
    const vols = $allVolunteers ?? []
    const vss = $allVolunteerShifts ?? []

    return visibleDepts.map(dept => {
      const deptShifts = shifts.filter(s => s.department_id === dept.id)
      const days = {}
      for (const s of deptShifts) {
        if (!days[s.day]) days[s.day] = []
        const assigned = vss.filter(vs => vs.shift_id === s.id).map(vs => ({
          vs,
          volunteer: vols.find(v => v.id === vs.volunteer_id),
        })).filter(x => x.volunteer)
        const hasConflict = assigned.some(({ volunteer }) =>
          checkConflict(volunteer.id, s.id, vss, shifts)
        )
        days[s.day].push({ shift: s, assigned, hasConflict })
      }
      return {
        dept,
        days: Object.entries(days).sort(([a], [b]) => a.localeCompare(b)),
      }
    })
  })

  function checkConflict(volunteerID, shiftID, vss, shifts) {
    const target = shifts.find(s => s.id === shiftID)
    if (!target) return false
    return vss
      .filter(vs => vs.volunteer_id === volunteerID && vs.shift_id !== shiftID)
      .some(vs => {
        const s = shifts.find(sh => sh.id === vs.shift_id)
        return s && s.day === target.day &&
          s.start_time < target.end_time &&
          target.start_time < s.end_time
      })
  }

  function startEdit(s) {
    editShiftID = s.id
    editShift = { ...s }
  }

  function cancelEdit() {
    editShiftID = null
    editShift = {}
  }

  async function saveShift() {
    saving = true
    error = ''
    try {
      await api.shifts.update(editShiftID, editShift)
      await db.shifts.put({ ...editShift, id: editShiftID })
      cancelEdit()
    } catch (err) {
      error = err.message
    } finally {
      saving = false
    }
  }

  async function reorder(shiftId, delta, siblings) {
    const idx = siblings.findIndex(({ shift }) => shift.id === shiftId)
    const newIdx = idx + delta
    if (newIdx < 0 || newIdx >= siblings.length) return

    // Swap in a copy, then assign sequential positions 0, 1, 2, …
    const reordered = [...siblings]
    ;[reordered[idx], reordered[newIdx]] = [reordered[newIdx], reordered[idx]]
    const positions = reordered.map(({ shift }, i) => ({ id: shift.id, position: i }))

    try {
      const res = await api.shifts.reorder(positions)
      if (res && !res.ok) throw new Error()
      for (const p of positions) {
        const s = await db.shifts.get(p.id)
        if (s) await db.shifts.put({ ...s, position: p.position })
      }
    } catch (err) {
      error = err.message
    }
  }

  function startAssign(shiftId) {
    assigningShiftID = shiftId
    assignVolID = 0
  }

  async function doAssign(shiftId) {
    if (!assignVolID) return
    assigning = true
    error = ''
    try {
      const res = await api.shifts.assignVolunteer(shiftId, assignVolID)
      if (res.status === 409) {
        const body = await res.json().catch(() => ({}))
        error = `Conflict: ${body.conflicting_shifts?.map(s => s.name).join(', ') ?? 'scheduling conflict'} — check the volunteer's other shifts.`
        return
      } else if (!res.ok) {
        const body = await res.json().catch(() => ({}))
        error = body.error || 'Assignment failed'
        return
      }
      await db.volunteer_shifts.put({ volunteer_id: assignVolID, shift_id: shiftId, confirmed: true, updated_at: new Date().toISOString() })
      assigningShiftID = null
      assignVolID = 0
    } catch (err) {
      error = err.message
    } finally {
      assigning = false
    }
  }

  async function doAssignForce(shiftId) {
    if (!assignVolID) return
    assigning = true
    error = ''
    try {
      const res = await api.shifts.assignVolunteer(shiftId, assignVolID, true)
      if (!res.ok) {
        const body = await res.json().catch(() => ({}))
        error = body.error || 'Assignment failed'
        return
      }
      await db.volunteer_shifts.put({ volunteer_id: assignVolID, shift_id: shiftId, confirmed: true, updated_at: new Date().toISOString() })
      assigningShiftID = null
      assignVolID = 0
    } catch (err) {
      error = err.message
    } finally {
      assigning = false
    }
  }

  async function unassign(shiftId, volunteerId) {
    error = ''
    try {
      await api.shifts.unassignVolunteer(shiftId, volunteerId)
      await db.volunteer_shifts.delete([volunteerId, shiftId])
    } catch (err) {
      error = err.message
    }
  }

  function fmt(t) {
    if (!t) return ''
    const [h, m] = t.split(':').map(Number)
    const ampm = h < 12 ? 'am' : 'pm'
    return `${h % 12 || 12}:${String(m).padStart(2, '0')}${ampm}`
  }
</script>

<div class="page">
  <div class="page-header">
    <h1 class="page-title">Schedule Board</h1>
  </div>

  {#if error}
    <div class="alert alert-error">{error}</div>
  {/if}

  {#if ($allShifts ?? []).length === 0}
    <div class="empty">
      <strong>No shifts yet</strong>
      <p>Create shifts in the Shifts page first.</p>
    </div>
  {:else}
    {#each board as { dept, days }}
      {#if days.length > 0}
        <div class="board-dept">
          <div class="board-dept-header">
            <span class="dept-dot" style="background:{dept.color}"></span>
            {dept.name}
          </div>

          {#each days as [day, rows]}
            <div class="board-day-label">{day}</div>

            {#each rows as { shift, assigned, hasConflict }, i}
              <div class="board-shift {hasConflict ? 'board-shift-conflict' : ''}">
                {#if editShiftID === shift.id}
                  <!-- Inline edit form -->
                  <div class="board-edit-form">
                    <div class="board-edit-grid">
                      <div class="form-group">
                        <label for="es-name">Name</label>
                        <input id="es-name" bind:value={editShift.name} />
                      </div>
                      <div class="form-group">
                        <label for="es-day">Day</label>
                        <input id="es-day" bind:value={editShift.day} placeholder="YYYY-MM-DD" />
                      </div>
                      <div class="form-group">
                        <label for="es-start">Start</label>
                        <input id="es-start" type="time" bind:value={editShift.start_time} />
                      </div>
                      <div class="form-group">
                        <label for="es-end">End</label>
                        <input id="es-end" type="time" bind:value={editShift.end_time} />
                      </div>
                      <div class="form-group">
                        <label for="es-cap">Capacity</label>
                        <input id="es-cap" type="number" min="0" bind:value={editShift.capacity} />
                      </div>
                    </div>
                    <div class="actions">
                      <button class="btn btn-primary btn-sm" onclick={saveShift} disabled={saving}>
                        {saving ? '…' : 'Save'}
                      </button>
                      <button class="btn btn-ghost btn-sm" onclick={cancelEdit}>Cancel</button>
                    </div>
                  </div>
                {:else}
                  <div class="board-shift-main">
                    <div class="board-shift-meta">
                      <strong>{shift.name}</strong>
                      <span class="text-muted">{fmt(shift.start_time)}–{fmt(shift.end_time)}</span>
                      {#if shift.capacity > 0}
                        <span class="board-cap {assigned.length >= shift.capacity ? 'board-cap-full' : ''}">
                          {assigned.length}/{shift.capacity}
                        </span>
                      {:else if assigned.length > 0}
                        <span class="board-cap">{assigned.length}</span>
                      {/if}
                      {#if hasConflict}
                        <span class="badge badge-lead" style="margin-left:0.3rem">⚠ conflict</span>
                      {/if}
                    </div>

                    <div class="board-shift-actions">
                      <button class="btn btn-ghost btn-sm" onclick={() => startEdit(shift)}>Edit</button>
                      <button class="btn btn-ghost btn-sm" title="Move up"
                        onclick={() => reorder(shift.id, -1, rows)}>↑</button>
                      <button class="btn btn-ghost btn-sm" title="Move down"
                        onclick={() => reorder(shift.id, 1, rows)}>↓</button>
                    </div>
                  </div>

                  <!-- Assigned volunteers -->
                  {#if assigned.length > 0}
                    <div class="board-volunteers">
                      {#each assigned as { vs, volunteer }}
                        <div class="board-vol-chip">
                          {volunteer.name}
                          {#if checkConflict(volunteer.id, shift.id, $allVolunteerShifts ?? [], $allShifts ?? [])}
                            <span title="Scheduling conflict" style="color:var(--c-warn)">⚠</span>
                          {/if}
                          <button class="board-vol-remove" onclick={() => unassign(shift.id, volunteer.id)} title="Remove">×</button>
                        </div>
                      {/each}
                    </div>
                  {/if}

                  <!-- Assign volunteer -->
                  {#if assigningShiftID === shift.id}
                    <div class="board-assign-row">
                      <select bind:value={assignVolID} style="width:auto">
                        <option value={0}>— Select volunteer —</option>
                        {#each $allVolunteers ?? [] as v}
                          <option value={v.id}>{v.name}</option>
                        {/each}
                      </select>
                      <button class="btn btn-primary btn-sm" onclick={() => doAssign(shift.id)} disabled={!assignVolID || assigning}>
                        {assigning ? '…' : 'Assign'}
                      </button>
                      <button class="btn btn-ghost btn-sm" onclick={() => doAssignForce(shift.id)} disabled={!assignVolID || assigning} title="Assign ignoring conflicts">
                        Force
                      </button>
                      <button class="btn btn-ghost btn-sm" onclick={() => { assigningShiftID = null; assignVolID = 0 }}>Cancel</button>
                    </div>
                  {:else}
                    <button class="board-add-vol" onclick={() => startAssign(shift.id)}>+ Assign volunteer</button>
                  {/if}
                {/if}
              </div>
            {/each}
          {/each}
        </div>
      {/if}
    {/each}
  {/if}
</div>

<style>
  .board-dept {
    margin-bottom: 2rem;
  }
  .board-dept-header {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    font-size: 1rem;
    font-weight: 700;
    margin-bottom: 0.5rem;
    padding-bottom: 0.5rem;
    border-bottom: 1px solid var(--c-border);
  }
  .board-day-label {
    font-size: 0.75rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--c-muted);
    margin: 0.75rem 0 0.35rem;
  }
  .board-shift {
    background: var(--c-surface);
    border: 1px solid var(--c-border);
    border-radius: 8px;
    padding: 0.85rem 1rem;
    margin-bottom: 0.5rem;
  }
  .board-shift-conflict {
    border-color: rgba(245,158,11,0.4);
  }
  .board-shift-main {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 1rem;
  }
  .board-shift-meta {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    flex-wrap: wrap;
    font-size: 0.875rem;
  }
  .board-shift-actions {
    display: flex;
    gap: 0.25rem;
    flex-shrink: 0;
  }
  .board-cap {
    font-size: 0.75rem;
    background: rgba(99,102,241,0.12);
    color: var(--c-accent-h);
    padding: 0.1rem 0.4rem;
    border-radius: 99px;
  }
  .board-cap-full {
    background: rgba(239,68,68,0.12);
    color: var(--c-danger);
  }
  .board-volunteers {
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem;
    margin-top: 0.6rem;
  }
  .board-vol-chip {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    background: rgba(99,102,241,0.12);
    color: var(--c-accent-h);
    padding: 0.2rem 0.5rem;
    border-radius: 99px;
    font-size: 0.78rem;
    font-weight: 500;
  }
  .board-vol-remove {
    background: none;
    border: none;
    color: var(--c-muted);
    cursor: pointer;
    font-size: 1rem;
    line-height: 1;
    padding: 0;
    margin-left: 0.15rem;
  }
  .board-vol-remove:hover { color: var(--c-danger); }
  .board-add-vol {
    background: none;
    border: none;
    color: var(--c-muted);
    cursor: pointer;
    font-size: 0.78rem;
    padding: 0.35rem 0;
    margin-top: 0.35rem;
    font-family: var(--font);
  }
  .board-add-vol:hover { color: var(--c-text); }
  .board-assign-row {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    margin-top: 0.5rem;
    flex-wrap: wrap;
  }
  .board-edit-form {
    padding: 0.25rem 0;
  }
  .board-edit-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
    gap: 0.75rem;
    margin-bottom: 0.75rem;
  }
</style>
