<script setup lang="ts">
// 내 업무 — 담당/지시 두 뷰를 탭으로 전환, 상태 그룹별 업무 목록 (API 연동)
// 검색/프로젝트/정렬은 서버에서 처리(담당·지시 양쪽에 적용, 페이지네이션과 일관)
import { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue'
import { storeToRefs } from 'pinia'
import { RouterLink } from 'vue-router'
import AppShell from '@/layouts/AppShell.vue'
import UserAvatar from '@/components/UserAvatar.vue'
import DropdownSelect from '@/components/DropdownSelect.vue'
import { useMyTaskStore } from '@/stores/my-task.store'
import { useProjectStore } from '@/stores/project.store'
import { countActive, type MyTaskRow } from '@/mock/relay.mock'
import type { MyTaskListQuery, MyTaskSort } from '@/types/my-task'

type View = 'assigned' | 'issued'
const view = ref<View>('assigned')

// 검색/프로젝트/정렬 필터
const keyword = ref('')
const projectFilter = ref<string>('all')
const sort = ref<MyTaskSort>('due')
const SORT_OPTIONS: { value: MyTaskSort; label: string }[] = [
  { value: 'due', label: '마감 임박순' },
  { value: 'recent', label: '최근 등록순' },
]

const myTaskStore = useMyTaskStore()

// 프로젝트 필터 드롭다운 옵션 — 프로젝트 목록을 불러와 채운다('모든 프로젝트' + 각 프로젝트)
const projectStore = useProjectStore()
const { projects } = storeToRefs(projectStore)
const projectOptions = computed(() => [
  { value: 'all', label: '모든 프로젝트' },
  ...projects.value.map((p) => ({ value: p.id, label: p.name })),
])

// 현재 검색/프로젝트/정렬 조건 → 내 업무 쿼리
function currentQuery(): MyTaskListQuery {
  const q = keyword.value.trim()
  return {
    ...(q ? { q } : {}),
    ...(projectFilter.value !== 'all' ? { projectId: projectFilter.value } : {}),
    sort: sort.value,
  }
}
function loadAll() {
  void myTaskStore.fetchAll(currentQuery())
}

onMounted(() => {
  void projectStore.fetchList()
  loadAll()
})

// 프로젝트/정렬 변경 시 즉시 재조회
watch([projectFilter, sort], loadAll)

// 검색어는 디바운스 후 재조회(연속 입력 시 호출 폭주 방지)
let searchTimer: ReturnType<typeof setTimeout> | null = null
watch(keyword, () => {
  if (searchTimer) clearTimeout(searchTimer)
  searchTimer = setTimeout(loadAll, 250)
})
onBeforeUnmount(() => {
  if (searchTimer) clearTimeout(searchTimer)
})

// 행 클릭 → 항상 업무 상세(TaskDetailPage). 역할 기반 액션은 상세에서 분기한다
function taskLink(row: MyTaskRow): string {
  return `/projects/${row.projectId}/tasks/${row.id}`
}

const groups = computed(() => (view.value === 'assigned' ? myTaskStore.assigned : myTaskStore.issued))

const assignedCount = computed(() => countActive(myTaskStore.assigned))
const issuedCount = computed(() => countActive(myTaskStore.issued))
// 지시 뷰의 승인 대기(내 승인 필요) 건수
const issuedReviewCount = computed(
  () => myTaskStore.issued.find((g) => g.key === 'review')?.rows.length ?? 0,
)
// 승인 대기 강조 배너는 지시 뷰에서 표시
const showPendingNote = computed(() => view.value === 'issued' && issuedReviewCount.value > 0)

const loading = computed(() => myTaskStore.loading)
const isEmpty = computed(() => !loading.value && groups.value.length === 0)

// 더보기 — 현재 뷰(담당/지시) 기준
const hasMore = computed(() =>
  view.value === 'assigned' ? myTaskStore.assignedHasMore : myTaskStore.issuedHasMore,
)
const loadingMore = computed(() => myTaskStore.loadingMore)
function loadMore() {
  if (view.value === 'assigned') void myTaskStore.loadMoreAssigned()
  else void myTaskStore.loadMoreIssued()
}
</script>

<template>
  <AppShell>
    <div class="page">
      <div class="pagehead">
        <h1>내 업무</h1>
        <span class="sub">나에게 배정되었거나 내가 지시한 업무를 한곳에서 관리하세요.</span>
      </div>

      <!-- 담당 / 지시 토글 -->
      <div class="viewtabs">
        <button
          class="viewtab"
          :class="{ active: view === 'assigned' }"
          type="button"
          @click="view = 'assigned'"
        >
          <span class="tb-label">담당 업무</span>
          <span class="vt-count">{{ assignedCount }}</span>
        </button>
        <button
          class="viewtab"
          :class="{ active: view === 'issued' }"
          type="button"
          @click="view = 'issued'"
        >
          <span class="tb-label">지시한 업무</span>
          <span class="vt-count">{{ issuedCount }}</span>
          <span
            v-if="issuedReviewCount > 0"
            class="vt-flag"
          >승인 대기 {{ issuedReviewCount }}</span>
        </button>
      </div>

      <!-- 툴바 -->
      <div class="toolbar">
        <div class="search">
          <svg
            viewBox="0 0 24 24"
            fill="none"
            stroke="currentColor"
            stroke-width="2"
          >
            <circle
              cx="11"
              cy="11"
              r="7"
            /><path d="m21 21-4-4" />
          </svg>
          <input
            v-model="keyword"
            type="text"
            placeholder="업무 검색…"
          >
        </div>
        <DropdownSelect
          v-model="projectFilter"
          :options="projectOptions"
          align="left"
          aria-label="프로젝트 필터"
        >
          <template #icon>
            <svg
              viewBox="0 0 24 24"
              fill="none"
              stroke="currentColor"
              stroke-width="2"
              stroke-linecap="round"
              stroke-linejoin="round"
            >
              <path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20" />
              <path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z" />
            </svg>
          </template>
        </DropdownSelect>
        <DropdownSelect
          v-model="sort"
          :options="SORT_OPTIONS"
          push-right
          align="right"
          aria-label="정렬"
        >
          <template #icon>
            <svg
              viewBox="0 0 24 24"
              fill="none"
              stroke="currentColor"
              stroke-width="2"
              stroke-linecap="round"
              stroke-linejoin="round"
            >
              <path d="M11 5h10M11 9h7M11 13h4M3 17l3 3 3-3M6 18V4" />
            </svg>
          </template>
        </DropdownSelect>
      </div>

      <!-- 승인 대기 강조 배너 (지시 뷰) -->
      <div
        v-if="showPendingNote"
        class="pending-note"
      >
        <svg
          viewBox="0 0 24 24"
          fill="none"
          stroke="currentColor"
          stroke-width="2"
          stroke-linecap="round"
          stroke-linejoin="round"
        >
          <path d="M12 8v4l3 2" /><circle
            cx="12"
            cy="12"
            r="9"
          />
        </svg>
        <span><b>{{ issuedReviewCount }}건</b>의 업무가 내 승인을 기다리고 있어요. 검토 후 승인하거나 수정을 요청하세요.</span>
      </div>

      <!-- 로딩 / 빈 상태 -->
      <div
        v-if="loading"
        class="state-msg"
      >
        내 업무를 불러오는 중…
      </div>
      <div
        v-else-if="isEmpty"
        class="state-msg"
      >
        {{ view === 'assigned' ? '담당 중인 업무가 없습니다.' : '지시한 업무가 없습니다.' }}
      </div>

      <!-- 상태 그룹 -->
      <div
        v-for="group in groups"
        :key="group.key"
        class="group"
      >
        <div class="group-head">
          <span
            class="gh-dot"
            :class="group.key"
          />
          <span class="gh-label">{{ group.label }}</span>
          <span class="gh-count">{{ group.rows.length }}</span>
          <span
            v-if="group.action"
            class="gh-action"
          >{{ group.action }}</span>
        </div>
        <div
          class="list"
          :class="{ attn: group.attn }"
        >
          <RouterLink
            v-for="row in group.rows"
            :key="row.id"
            class="task-row"
            :class="{ 'is-done': row.done }"
            :to="taskLink(row)"
          >
            <span
              class="st-dot"
              :class="row.status"
            />
            <span class="task-main">
              <span class="task-title">
                <span class="ttext">{{ row.title }}</span>
                <span class="tid">#{{ row.id }}</span>
              </span>
              <span class="task-meta">
                <span class="repo-chip">
                  <svg
                    viewBox="0 0 24 24"
                    fill="none"
                    stroke="currentColor"
                    stroke-width="2"
                    stroke-linecap="round"
                    stroke-linejoin="round"
                  >
                    <path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20" />
                    <path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z" />
                  </svg>
                  {{ row.projectName }}
                </span>
                <span class="meta-sep" />
                <span
                  v-if="row.checklist"
                  class="mi"
                >
                  <svg
                    viewBox="0 0 24 24"
                    fill="none"
                    stroke="currentColor"
                    stroke-width="2"
                    stroke-linecap="round"
                    stroke-linejoin="round"
                  >
                    <path d="M9 11l3 3L22 4" />
                    <path d="M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11" />
                  </svg>
                  {{ row.checklist[0] }}/{{ row.checklist[1] }}
                </span>
                <span
                  v-if="row.checklist"
                  class="meta-sep"
                />
                <!-- 지시 뷰: 담당자 아바타 + (강조 아닌) 보조 텍스트 -->
                <span
                  v-if="row.assignees && !row.metaAttn"
                  class="mi"
                >
                  <span class="mini-stack">
                    <span
                      v-for="a in (row.assignees ?? []).slice(0, 3)"
                      :key="a.id"
                      class="mini-av"
                    ><UserAvatar
                      :url="a.avatarUrl"
                      :name="a.name"
                    /></span>
                    <span
                      v-if="(row.assignees?.length ?? 0) > 3"
                      class="mini-av mini-more"
                    >+{{ (row.assignees?.length ?? 0) - 3 }}</span>
                  </span>
                  {{ row.metaText }}
                </span>
                <!-- 지시 뷰 승인대기: 아바타와 강조 텍스트를 분리 표기 -->
                <template v-else-if="row.assignees && row.metaAttn">
                  <span class="mi">
                    <span class="mini-stack">
                      <span
                        v-for="a in (row.assignees ?? []).slice(0, 3)"
                        :key="a.id"
                        class="mini-av"
                      ><UserAvatar
                        :url="a.avatarUrl"
                        :name="a.name"
                      /></span>
                      <span
                        v-if="(row.assignees?.length ?? 0) > 3"
                        class="mini-av mini-more"
                      >+{{ (row.assignees?.length ?? 0) - 3 }}</span>
                    </span>
                  </span>
                  <span class="meta-sep" />
                  <span class="mi attn">{{ row.metaText }}</span>
                </template>
                <!-- 담당 뷰: 보조 텍스트만 -->
                <span
                  v-else-if="row.metaText"
                  class="mi"
                >{{ row.metaText }}</span>
              </span>
            </span>
            <span class="task-right">
              <span
                class="due"
                :class="{ overdue: row.overdue }"
              >
                <template v-if="row.dday">
                  <svg
                    v-if="row.overdue"
                    viewBox="0 0 24 24"
                    fill="none"
                    stroke="currentColor"
                    stroke-width="2"
                    stroke-linecap="round"
                    stroke-linejoin="round"
                  >
                    <circle
                      cx="12"
                      cy="12"
                      r="9"
                    /><path d="M12 7v5l3 2" />
                  </svg>
                  <svg
                    v-else
                    viewBox="0 0 24 24"
                    fill="none"
                    stroke="currentColor"
                    stroke-width="2"
                    stroke-linecap="round"
                    stroke-linejoin="round"
                  >
                    <rect
                      x="3"
                      y="4"
                      width="18"
                      height="18"
                      rx="2"
                    /><path d="M16 2v4M8 2v4M3 10h18" />
                  </svg>
                  {{ row.dueLabel }} <span
                    class="dday"
                    :class="row.ddayLevel"
                  >{{ row.dday }}</span>
                </template>
                <template v-else>{{ row.dueLabel }}</template>
              </span>
              <span
                v-if="row.reviewBtn"
                class="review-btn"
              >검토하기</span>
              <span
                v-else-if="row.statusLabel"
                class="st-badge"
                :class="row.status"
              >{{ row.statusLabel }}</span>
            </span>
          </RouterLink>
        </div>
      </div>

      <!-- 더보기 -->
      <button
        v-if="hasMore"
        class="load-more"
        type="button"
        :disabled="loadingMore"
        @click="loadMore"
      >
        {{ loadingMore ? '불러오는 중…' : '더보기' }}
      </button>
    </div>
  </AppShell>
</template>

<style scoped>
.pagehead {
  display: flex;
  align-items: flex-end;
  gap: 0.75rem;
  padding: 1.5rem 0 1rem;
}
.pagehead h1 {
  font-size: 1.375rem;
  font-weight: 700;
  letter-spacing: -0.025rem;
  white-space: nowrap;
}
.pagehead .sub {
  font-size: 0.8125rem;
  color: var(--text-2);
  padding-bottom: 0.125rem;
  white-space: nowrap;
}

/* 담당/지시 토글 */
.viewtabs {
  display: flex;
  gap: 0.25rem;
  border-bottom: 1px solid var(--border);
  margin-bottom: 1.125rem;
}
.viewtab {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.625rem 0.25rem;
  margin-right: 1.125rem;
  font-size: 0.875rem;
  font-weight: 600;
  line-height: 1;
  color: var(--text-2);
  background: none;
  border: none;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
  cursor: pointer;
  white-space: nowrap;
  font-family: inherit;
}
.viewtab .tb-label {
  line-height: 1;
}
.viewtab:hover {
  color: var(--text);
}
.viewtab.active {
  color: var(--accent);
  border-bottom-color: var(--accent);
}
.viewtab .vt-count {
  font-size: 0.6875rem;
  font-weight: 600;
  color: var(--text-2);
  background: #f1f2f4;
  border-radius: 20px;
  height: 1.0625rem;
  min-width: 1.0625rem;
  padding: 0 0.375rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  line-height: 1;
}
.viewtab.active .vt-count {
  background: var(--accent-weak);
  color: var(--accent);
}
.viewtab .vt-flag {
  font-size: 0.6875rem;
  font-weight: 600;
  color: var(--amber);
  background: var(--amber-weak);
  border: 1px solid var(--amber-border);
  border-radius: 20px;
  padding: 0.0625rem 0.4375rem;
  line-height: 1.4;
  white-space: nowrap;
}

.toolbar .search {
  width: 16.25rem;
}
/* 승인 대기 강조 배너 */
.pending-note {
  display: flex;
  align-items: center;
  gap: 0.625rem;
  padding: 0.6875rem 0.9375rem;
  background: var(--amber-weak);
  border: 1px solid var(--amber-border);
  border-radius: 0.5625rem;
  margin-bottom: 1.375rem;
  font-size: 0.8125rem;
  color: #8a5a12;
}
.pending-note svg {
  width: 1.0625rem;
  height: 1.0625rem;
  color: var(--amber);
  flex-shrink: 0;
}
.pending-note b {
  font-weight: 700;
}

/* 로딩/빈 상태 */
.state-msg {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 0.625rem;
  box-shadow: var(--shadow-sm);
  padding: 2.5rem 1.25rem;
  text-align: center;
  font-size: 0.844rem;
  color: var(--text-3);
}

/* 상태 그룹 */
.group {
  margin-bottom: 1.375rem;
}
.group-head {
  display: flex;
  align-items: center;
  gap: 0.5625rem;
  margin-bottom: 0.5625rem;
  padding-left: 0.125rem;
}
.gh-dot {
  width: 0.5625rem;
  height: 0.5625rem;
  border-radius: 50%;
  flex-shrink: 0;
}
.gh-dot.changes {
  background: var(--red);
}
.gh-dot.prog {
  background: var(--blue);
}
.gh-dot.todo {
  background: #c4c8cf;
}
.gh-dot.review {
  background: var(--amber);
}
.gh-dot.done {
  background: var(--green);
}
.gh-label {
  font-size: 0.8125rem;
  font-weight: 700;
  color: var(--text);
  white-space: nowrap;
}
.gh-count {
  font-size: 0.719rem;
  font-weight: 600;
  color: var(--text-2);
  background: #eceef1;
  border-radius: 20px;
  height: 1.125rem;
  min-width: 1.125rem;
  padding: 0 0.375rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  line-height: 1;
}
.gh-action {
  margin-left: 0.25rem;
  font-size: 0.719rem;
  font-weight: 600;
  color: var(--amber);
  white-space: nowrap;
}

.list.attn {
  border-color: var(--amber-border);
  box-shadow:
    0 0 0 3px rgba(183, 121, 31, 0.08),
    var(--shadow-sm);
}

/* 업무 행 */
.task-row {
  display: flex;
  align-items: center;
  gap: 0.875rem;
  padding: 0.8125rem 1.125rem;
  border-top: 1px solid var(--border);
  cursor: pointer;
  text-decoration: none;
  color: inherit;
}
.task-row:first-child {
  border-top: none;
}
.task-row:hover {
  background: #fafbfc;
}
.task-main {
  flex: 1;
  min-width: 0;
}
.task-title {
  font-size: 0.875rem;
  font-weight: 600;
  color: var(--text);
  display: flex;
  align-items: center;
  gap: 0.5rem;
}
.task-title .ttext {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.task-title .tid {
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--text-3);
  flex-shrink: 0;
}
.task-row:hover .task-title .ttext {
  color: var(--accent);
}
.task-row.is-done .task-title {
  color: var(--text-2);
}
.task-meta {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin-top: 0.25rem;
  font-size: 0.75rem;
  color: var(--text-3);
}
.repo-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.3125rem;
  font-weight: 600;
  color: var(--text-2);
  white-space: nowrap;
}
.repo-chip svg {
  width: 0.8125rem;
  height: 0.8125rem;
  color: var(--accent);
  flex-shrink: 0;
}
.mi {
  display: inline-flex;
  align-items: center;
  gap: 0.375rem;
  white-space: nowrap;
}
.mi svg {
  width: 0.8125rem;
  height: 0.8125rem;
}
.mi.attn {
  color: var(--amber);
  font-weight: 600;
}
.meta-sep {
  width: 0.1875rem;
  height: 0.1875rem;
  border-radius: 50%;
  background: #d7dae0;
  flex-shrink: 0;
}

/* 담당자 미니 아바타 스택 */
.mini-stack {
  display: inline-flex;
  align-items: center;
}
.mini-av {
  width: 1.125rem;
  height: 1.125rem;
  border-radius: 50%;
  display: grid;
  place-items: center;
  font-size: 0.5625rem;
  font-weight: 700;
  color: #fff;
  box-shadow: 0 0 0 1.5px #fff;
  flex-shrink: 0;
}
.mini-stack .mini-av + .mini-av {
  margin-left: -0.3125rem;
}
/* 초과 인원 표기(+N) */
.mini-av.mini-more {
  background: #eceef1;
  color: var(--text-2);
}

.task-right {
  display: flex;
  align-items: center;
  gap: 0.875rem;
  flex-shrink: 0;
}
.due {
  display: flex;
  align-items: center;
  gap: 0.375rem;
  font-size: 0.781rem;
  color: var(--text-2);
  font-weight: 500;
  white-space: nowrap;
}
.due svg {
  width: 0.875rem;
  height: 0.875rem;
  color: var(--text-3);
}
.due.overdue {
  color: var(--red);
  font-weight: 600;
}
.due.overdue svg {
  color: var(--red);
}
.dday {
  font-size: 0.6875rem;
  font-weight: 700;
  padding: 0.0625rem 0.4375rem;
  border-radius: 20px;
  white-space: nowrap;
  line-height: 1.5;
}
.dday.urgent {
  color: var(--red);
  background: var(--red-weak);
  border: 1px solid var(--red-border);
}
.dday.soon {
  color: var(--amber);
  background: var(--amber-weak);
  border: 1px solid var(--amber-border);
}
.dday.calm {
  color: var(--text-2);
  background: #f1f2f4;
  border: 1px solid var(--border);
}
.task-right .st-badge {
  min-width: 4rem;
}
.review-btn {
  font-size: 0.75rem;
  font-weight: 600;
  color: #fff;
  background: var(--amber);
  border: 1px solid var(--amber);
  border-radius: var(--radius);
  padding: 0.3125rem 0.6875rem;
  white-space: nowrap;
}
</style>
