<script setup>
import { onBeforeUnmount, ref } from 'vue'
import GuideTooltip from './GuideTooltip.vue'

const props = defineProps({
  dateMain: {
    type: String,
    required: true,
  },
  dateWeekday: {
    type: String,
    required: true,
  },
  dateWeekdayTone: {
    type: String,
    default: 'text-ink',
  },
  dday: {
    type: String,
    default: '',
  },
  showDday: {
    type: Boolean,
    default: true,
  },
  comment: {
    type: String,
    required: true,
  },
  totalTime: {
    type: String,
    required: true,
  },
  tasks: {
    type: Array,
    required: true,
  },
  memo: {
    type: Array,
    required: true,
  },
  hours: {
    type: Array,
    required: true,
  },
  timetable: {
    type: Array,
    required: true,
  },
  brand: {
    type: String,
    default: 'SORI.STUDIO',
  },
  readonly: {
    type: Boolean,
    default: false,
  },
})

const emit = defineEmits([
  'update:comment',
  'update:task-label',
  'update:task-title',
  'toggle:task',
  'clear:tasks',
  'update:memo-label',
  'update:memo',
  'update:timetable',
])

let dragState = null
let taskSelectionDrag = null
const selectedTaskIndexes = ref(new Set())

function shouldShowTaskPlaceholder(index) {
  return index === 0 && props.tasks.every((task) => !task.title.trim())
}

function buildTimedRange(baseTimetable, startIndex, endIndex, nextValue) {
  const nextTimetable = [...baseTimetable]
  const rangeStart = Math.min(startIndex, endIndex)
  const rangeEnd = Math.max(startIndex, endIndex)

  for (let index = rangeStart; index <= rangeEnd; index += 1) {
    nextTimetable[index] = nextValue
  }

  return nextTimetable
}

function startTimetableDrag(index, event) {
  if (props.readonly) {
    return
  }

  if (event.button !== 0 && event.button !== 2) {
    return
  }

  const shouldFill = event.button === 2 ? false : !props.timetable[index]

  dragState = {
    startIndex: index,
    baseTimetable: [...props.timetable],
    nextValue: shouldFill,
  }

  emit('update:timetable', buildTimedRange(dragState.baseTimetable, index, index, dragState.nextValue))
}

function moveTimetableDrag(index) {
  if (props.readonly || !dragState) {
    return
  }

  emit(
    'update:timetable',
    buildTimedRange(dragState.baseTimetable, dragState.startIndex, index, dragState.nextValue),
  )
}

function stopTimetableDrag() {
  dragState = null
}

function isTaskSelectionBlockedTarget(target) {
  return Boolean(target.closest('button, textarea, [contenteditable="true"]'))
}

function getTaskSelectionRange(startIndex, endIndex) {
  const rangeStart = Math.min(startIndex, endIndex)
  const rangeEnd = Math.max(startIndex, endIndex)

  return new Set(Array.from({ length: rangeEnd - rangeStart + 1 }, (_, offset) => rangeStart + offset))
}

function isTaskSelected(index) {
  return selectedTaskIndexes.value.has(index)
}

function clearTaskSelection() {
  selectedTaskIndexes.value = new Set()
  taskSelectionDrag = null
}

function clearTaskSelectionOnFocus() {
  if (taskSelectionDrag) {
    return
  }

  clearTaskSelection()
}

function startTaskSelection(index, event) {
  if (props.readonly) {
    return
  }

  if (event.button !== 0 || isTaskSelectionBlockedTarget(event.target)) {
    return
  }

  selectedTaskIndexes.value = new Set()
  taskSelectionDrag = {
    startIndex: index,
    isSelecting: false,
  }
}

function moveTaskSelection(index) {
  if (!taskSelectionDrag) {
    return
  }

  if (!taskSelectionDrag.isSelecting && index === taskSelectionDrag.startIndex) {
    return
  }

  if (!taskSelectionDrag.isSelecting) {
    taskSelectionDrag.isSelecting = true
    document.activeElement?.blur?.()
    window.getSelection()?.removeAllRanges?.()
  }

  selectedTaskIndexes.value = getTaskSelectionRange(taskSelectionDrag.startIndex, index)
}

function moveTaskSelectionFromPointer(event) {
  if (!taskSelectionDrag) {
    return
  }

  const taskRow = document.elementFromPoint(event.clientX, event.clientY)?.closest('[data-task-index]')
  const index = Number(taskRow?.dataset.taskIndex)

  if (Number.isInteger(index)) {
    moveTaskSelection(index)
  }
}

function stopTaskSelection() {
  if (taskSelectionDrag && !taskSelectionDrag.isSelecting) {
    selectedTaskIndexes.value = new Set()
  }

  taskSelectionDrag = null
}

function clearSelectedTasks(event) {
  if (props.readonly) {
    return
  }

  if (selectedTaskIndexes.value.size === 0) {
    return
  }

  if (event.key === 'Escape') {
    event.preventDefault()
    clearTaskSelection()
    return
  }

  if (!['Backspace', 'Delete'].includes(event.key)) {
    return
  }

  event.preventDefault()
  emit('clear:tasks', [...selectedTaskIndexes.value])
  clearTaskSelection()
}

window.addEventListener('pointerup', stopTimetableDrag)
window.addEventListener('pointermove', moveTaskSelectionFromPointer)
window.addEventListener('pointerup', stopTaskSelection)
window.addEventListener('keydown', clearSelectedTasks)
onBeforeUnmount(() => {
  window.removeEventListener('pointerup', stopTimetableDrag)
  window.removeEventListener('pointermove', moveTaskSelectionFromPointer)
  window.removeEventListener('pointerup', stopTaskSelection)
  window.removeEventListener('keydown', clearSelectedTasks)
})
</script>

<template>
  <article
    class="planner-sheet flex w-full max-w-[762px] flex-col gap-3 bg-paper px-4 py-4 text-[10px] font-bold tracking-[0.16em] text-ink shadow-paper sm:px-8 sm:py-8 lg:px-12 lg:py-12"
  >
    <div class="planner-sheet__meta flex flex-col gap-4 py-3 sm:py-[18px]">
      <div class="planner-sheet__meta-top flex flex-col gap-3 sm:gap-4" :class="props.showDday ? 'sm:flex-row' : ''">
        <div class="planner-field min-h-[82px] px-[10px] pt-[10px]" :class="props.showDday ? 'w-full sm:w-[394px] sm:flex-1' : 'w-full flex-1'">
          <div class="planner-field__header flex items-center gap-2 text-muted">
            <span class="shrink-0">YEAR / MONTH / DAY</span>
            <span class="h-px flex-1 bg-ink"></span>
          </div>
          <p class="pt-6 text-[11px] tracking-[0.2em] text-ink sm:text-sm">
            <span>{{ dateMain }}</span>
            <span class="ml-1" :class="dateWeekdayTone">{{ dateWeekday }}</span>
          </p>
        </div>
        <div v-if="props.showDday" class="planner-field min-h-[82px] w-full px-[10px] pt-[10px] sm:w-[210px]">
          <div class="planner-field__header flex items-center gap-2 text-muted">
            <span class="shrink-0">D-DAY</span>
            <span class="h-px flex-1 bg-ink"></span>
          </div>
          <p
            class="pt-6 text-[11px] tracking-[0.14em] text-ink sm:text-sm"
            style="
              display: -webkit-box;
              -webkit-line-clamp: 3;
              -webkit-box-orient: vertical;
              overflow: hidden;
              text-overflow: ellipsis;
              word-break: break-word;
            "
          >
            {{ dday }}
          </p>
        </div>
      </div>
      <div class="planner-sheet__meta-bottom flex flex-col gap-3 border-b border-ink pb-3 sm:gap-4 sm:pb-[18px] lg:flex-row">
        <div class="planner-field min-h-[82px] w-full flex-1 px-[10px] pt-[10px] lg:w-[394px]">
          <div class="planner-field__header flex items-center gap-2 text-muted">
            <span class="shrink-0">COMMENT</span>
            <span class="h-px flex-1 bg-ink"></span>
          </div>
          <textarea
            :value="comment"
            rows="3"
            :readonly="props.readonly"
            class="mt-3 h-[54px] w-full resize-none bg-transparent pt-2 text-[11px] font-semibold normal-case tracking-[0.06em] text-stone-700 outline-none placeholder:text-stone-400 sm:text-xs"
            placeholder="오늘의 코멘트를 적어 주세요."
            @input="emit('update:comment', $event.target.value)"
          />
        </div>
        <div class="planner-field min-h-[82px] w-full px-[10px] pt-[10px] lg:w-[210px]">
          <div class="planner-field__header flex items-center gap-2 text-muted">
            <span class="shrink-0">FOCUSED TIME</span>
            <span class="h-px flex-1 bg-ink"></span>
          </div>
          <p class="pt-6 text-[11px] tracking-[0.2em] text-ink sm:text-sm">{{ totalTime }}</p>
        </div>
      </div>
    </div>

    <div class="planner-sheet__body flex flex-col gap-5 py-[10px] lg:flex-row lg:gap-4">
      <div class="planner-sheet__lists flex w-full flex-1 flex-col gap-[21px] lg:w-[394px]">
        <section>
          <div class="flex items-center gap-2 text-muted">
            <span class="shrink-0">TASKS</span>
            <span
              v-if="selectedTaskIndexes.size > 0"
              class="shrink-0 rounded-full border border-ink/30 px-2 py-[1px] text-[8px] tracking-[0.12em] text-ink"
            >
              선택 {{ selectedTaskIndexes.size }}개 · DEL 삭제 · ESC 취소
            </span>
            <span class="h-px flex-1 bg-ink"></span>
          </div>
          <div>
            <div
              v-for="(task, index) in tasks"
              :key="task.id ?? index"
              :data-task-index="index"
              class="flex h-[38px] select-none items-center border-b transition-colors"
              :class="[
                index % 5 === 4 || index === tasks.length - 1 ? 'border-ink' : 'border-line',
                isTaskSelected(index) ? 'bg-amber-100/55' : '',
              ]"
              @pointerdown="startTaskSelection(index, $event)"
              @pointerenter="moveTaskSelection(index)"
            >
              <div class="h-full w-[52px] shrink-0 border-r border-dashed border-ink px-1.5 py-[7px] sm:w-[62px] sm:px-2">
                <input
                  :value="task.label"
                  type="text"
                  :readonly="props.readonly"
                  class="w-full bg-transparent text-center text-[9px] font-semibold tracking-[0.08em] text-stone-500 outline-none placeholder:text-stone-300"
                  @focus="clearTaskSelectionOnFocus"
                  @input="emit('update:task-label', { index, value: $event.target.value })"
                />
              </div>
              <div class="flex min-w-0 flex-1 items-center gap-2 px-2 sm:px-3">
                <input
                  :value="task.title"
                  type="text"
                  :readonly="props.readonly"
                  class="w-full truncate bg-transparent text-[10px] font-semibold normal-case tracking-[0.04em] text-stone-800 outline-none placeholder:text-stone-400 sm:text-[11px] sm:tracking-[0.06em]"
                  :placeholder="shouldShowTaskPlaceholder(index) ? '할 일을 입력해 주세요.' : ''"
                  @focus="clearTaskSelectionOnFocus"
                  @input="emit('update:task-title', { index, value: $event.target.value })"
                />
                <GuideTooltip
                  v-if="task.carryoverFrom"
                  :title="'이월된 할 일'"
                  :description="`이 항목은 ${task.carryoverFrom}부터 이월된 할 일입니다.`"
                  :dismissible="false"
                  button-label="이월"
                />
              </div>
              <div class="flex h-full w-[36px] shrink-0 items-center justify-center p-[8px] sm:w-[42px] sm:p-[10px]">
                <button
                  type="button"
                  :disabled="props.readonly"
                  class="flex h-full w-full items-center justify-center border border-dashed transition focus-visible:ring-2 focus-visible:ring-ink focus-visible:ring-offset-2 focus-visible:ring-offset-paper"
                  :class="task.checked ? 'border-ink bg-stone-100 text-ink' : 'border-ink/60 text-transparent'"
                  @click="emit('toggle:task', index)"
                >
                  <span class="text-sm leading-none">✓</span>
                </button>
              </div>
            </div>
          </div>
        </section>

        <section>
          <div class="flex items-center gap-2 text-muted">
            <span class="shrink-0">MEMO</span>
            <span class="h-px flex-1 bg-ink"></span>
          </div>
          <div>
            <div
              v-for="(memoItem, index) in memo"
              :key="`memo-${index}`"
              class="flex h-[38px] items-center border-b"
              :class="index === memo.length - 1 ? 'border-ink' : 'border-line'"
            >
              <div class="h-full w-[52px] shrink-0 border-r border-dashed border-ink px-1.5 py-[7px] sm:w-[62px] sm:px-2">
                <input
                  :value="memoItem.label"
                  type="text"
                  :readonly="props.readonly"
                  class="w-full bg-transparent text-center text-[9px] font-semibold tracking-[0.08em] text-stone-500 outline-none placeholder:text-stone-300"
                  @input="emit('update:memo-label', { index, value: $event.target.value })"
                />
              </div>
              <div class="flex flex-1 items-center px-2 sm:px-3">
                <input
                  :value="memoItem.text"
                  type="text"
                  :readonly="props.readonly"
                  class="w-full bg-transparent text-[10px] font-semibold normal-case tracking-[0.04em] text-stone-700 outline-none placeholder:text-stone-400 sm:text-[11px] sm:tracking-[0.06em]"
                  @input="emit('update:memo', { index, value: $event.target.value })"
                />
              </div>
            </div>
          </div>
        </section>
      </div>

      <section class="planner-sheet__timetable w-full shrink-0 lg:w-[210px]">
        <div class="flex items-center gap-2 text-muted">
          <span class="shrink-0">TIME TABLE</span>
          <span class="h-px flex-1 bg-ink"></span>
        </div>
        <div class="planner-sheet__timetable-scroll overflow-x-auto pb-1">
          <div class="planner-sheet__timetable-grid min-w-[210px]">
            <div
              v-for="(hour, index) in hours"
              :key="`${hour}-${index}`"
              class="flex h-[25px] border-b sm:h-[30px]"
              :class="index === hours.length - 1 ? 'border-ink' : 'border-line'"
            >
              <div
                class="flex h-full w-[30px] touch-none select-none items-center justify-center border-r border-ink text-[9px] text-ink"
                @pointerdown.prevent
              >
                {{ hour }}
              </div>
              <div
                v-for="quarter in 6"
                :key="quarter"
                :class="props.timetable[index * 6 + quarter - 1] ? 'bg-stone-800/90' : 'bg-transparent'"
                class="h-full w-[30px] cursor-crosshair border-r border-dashed border-line transition-colors last:border-r-0 touch-none select-none"
                @contextmenu.prevent
                @pointerdown.prevent="startTimetableDrag(index * 6 + quarter - 1, $event)"
                @pointerenter="moveTimetableDrag(index * 6 + quarter - 1)"
              />
            </div>
          </div>
        </div>
      </section>
    </div>

    <div class="flex justify-end">
      <p class="text-[10px] tracking-[0.18em] text-ink">{{ brand }}</p>
    </div>
  </article>
</template>
