<script setup lang="ts">
// 프로젝트 활동 — 날짜 그룹 단위 활동 피드 (API 연동)
import { computed, defineComponent, h, ref, watch } from 'vue'
import { useRoute, RouterLink } from 'vue-router'
import AppShell from '@/layouts/AppShell.vue'
import ProjectHeader from '@/components/ProjectHeader.vue'
import ProjectTabs from '@/components/ProjectTabs.vue'
import UserAvatar from '@/components/UserAvatar.vue'
import DropdownSelect from '@/components/DropdownSelect.vue'
import { useProjectStore } from '@/stores/project.store'
import { useActivityStore } from '@/stores/activity.store'
import type { Project, ActivityIcon } from '@/mock/relay.mock'

type Filter = 'all' | 'task' | 'member' | 'setting'

const route = useRoute()
const projectId = computed(() => String(route.params.projectId))
const projectStore = useProjectStore()
const activityStore = useActivityStore()

// 프로젝트 헤더 + 활동 피드 로딩
const repo = ref<Project | null>(null)
async function load() {
  try {
    repo.value = await projectStore.fetchOne(projectId.value)
  } catch {
    repo.value = null // 404/403 등은 인터셉터가 알림 처리
  }
  try {
    await activityStore.fetch(projectId.value)
  } catch {
    // 인터셉터가 알림 처리
  }
}
watch(projectId, load, { immediate: true })

const filter = ref<Filter>('all')
// 멤버 필터(행위자 id, 'all' = 전체). 피드는 전량 로드되므로 클라이언트에서 정확히 거른다.
const memberFilter = ref<string>('all')

// 피드에 등장한 행위자 목록(중복 제거) — 멤버 필터 드롭다운 옵션
const actorOptions = computed(() => {
  const map = new Map<string, string>()
  for (const d of activityStore.days) {
    for (const it of d.items) {
      if (it.actorId) map.set(it.actorId, it.actorName ?? '알 수 없음')
    }
  }
  return Array.from(map, ([id, name]) => ({ id, name }))
})
// 멤버 필터 드롭다운 옵션('모든 멤버' + 행위자들)
const memberOptions = computed(() => [
  { value: 'all', label: '모든 멤버' },
  ...actorOptions.value.map((a) => ({ value: a.id, label: a.name })),
])

// 유형/멤버 필터 적용 후 빈 날짜 그룹은 제거
const days = computed(() =>
  activityStore.days
    .map((d) => ({
      day: d.day,
      items: d.items.filter(
        (it) =>
          (filter.value === 'all' || it.tone === filter.value) &&
          (memberFilter.value === 'all' || it.actorId === memberFilter.value),
      ),
    }))
    .filter((d) => d.items.length > 0),
)

const memberCount = computed(() =>
  repo.value ? repo.value.members.length + repo.value.moreCount : 0,
)
const loading = computed(() => activityStore.loading)
const isEmpty = computed(() => !loading.value && days.value.length === 0)

// 활동 아이콘 — name 으로 SVG path 분기
const ACT_PATHS: Record<ActivityIcon, string> = {
  check: '<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"/>',
  pencil: '<path d="M12 20h9M16.5 3.5a2.1 2.1 0 0 1 3 3L7 19l-4 1 1-4Z"/>',
  'member-add': '<path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M19 8v6M22 11h-6"/>',
  'member-check': '<path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="m17 11 2 2 4-4"/>',
  'member-remove': '<path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M22 11h-6"/>',
  lock: '<rect x="3" y="11" width="18" height="11" rx="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/>',
  repo: '<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"/>',
}
const ActIcon = defineComponent({
  props: { name: { type: String, required: true } },
  setup(props) {
    return () =>
      h('svg', {
        viewBox: '0 0 24 24',
        fill: 'none',
        stroke: 'currentColor',
        'stroke-width': '2',
        'stroke-linecap': 'round',
        'stroke-linejoin': 'round',
        innerHTML: ACT_PATHS[props.name as ActivityIcon] ?? '',
      })
  },
})
</script>

<template>
  <AppShell>
    <div
      v-if="repo"
      class="page"
    >
      <div class="crumb">
        <RouterLink
          to="/projects"
          class="lnk"
        >
          프로젝트
        </RouterLink>
        <span class="sep">/</span>
        <RouterLink
          :to="`/projects/${repo.id}`"
          class="lnk"
        >
          {{ repo.name }}
        </RouterLink>
        <span class="sep">/</span>
        <b>활동</b>
      </div>

      <ProjectHeader
        :repo="repo"
        :meta-text="repo.updatedAgo"
      />
      <ProjectTabs
        :project-id="repo.id"
        active="activity"
        :task-count="repo.totalCount"
        :member-count="memberCount"
        :can-manage="repo.canManage"
      />

      <!-- 툴바 -->
      <div class="toolbar">
        <div class="segmented">
          <button
            :class="{ active: filter === 'all' }"
            @click="filter = 'all'"
          >
            전체
          </button>
          <button
            :class="{ active: filter === 'task' }"
            @click="filter = 'task'"
          >
            업무
          </button>
          <button
            :class="{ active: filter === 'member' }"
            @click="filter = 'member'"
          >
            멤버
          </button>
          <button
            :class="{ active: filter === 'setting' }"
            @click="filter = 'setting'"
          >
            설정
          </button>
        </div>
        <DropdownSelect
          v-model="memberFilter"
          :options="memberOptions"
          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="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2" /><circle
                cx="12"
                cy="7"
                r="4"
              />
            </svg>
          </template>
        </DropdownSelect>
      </div>

      <!-- 로딩 / 빈 상태 -->
      <div
        v-if="loading"
        class="feed-state"
      >
        활동을 불러오는 중입니다…
      </div>
      <div
        v-else-if="isEmpty"
        class="feed-state"
      >
        아직 기록된 활동이 없습니다.
      </div>

      <!-- 활동 피드 -->
      <!-- act-text 의 v-html 은 store 에서 사용자 입력을 escapeHtml 로 이스케이프한 뒤 신뢰 태그만 조립한 마크업이다 (XSS 위험 없음) -->
      <!-- eslint-disable vue/no-v-html -->
      <div
        v-else
        class="feed"
      >
        <div class="feed-inner">
          <template
            v-for="group in days"
            :key="group.day"
          >
            <div class="day">
              {{ group.day }}
            </div>
            <div
              v-for="(item, i) in group.items"
              :key="group.day + i"
              class="act"
              :class="{ 'last-in-group': i === group.items.length - 1 }"
            >
              <span
                class="act-ico"
                :class="item.tone"
              ><ActIcon :name="item.icon" /></span>
              <div class="act-main">
                <span class="act-av"><UserAvatar :url="item.avatarUrl" /></span>
                <span
                  class="act-text"
                  v-html="item.html"
                />
              </div>
              <span class="act-time">{{ item.time }}</span>
            </div>
          </template>
        </div>
      </div>
    </div>
  </AppShell>
</template>

<style scoped>
.crumb {
  padding: 1.125rem 0 0.75rem;
}

.toolbar {
  display: flex;
  align-items: center;
  gap: 0.625rem;
  margin-bottom: 0.5rem;
}

/* 활동 피드 */
.feed {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 0.625rem;
  box-shadow: var(--shadow-sm);
  padding: 0.375rem 1.25rem 1.125rem;
}
.feed-inner {
  position: relative;
}
.day {
  font-size: 0.75rem;
  font-weight: 700;
  color: var(--text-3);
  letter-spacing: 0.0125rem;
  padding: 1.125rem 0 0.375rem;
}
.act {
  display: flex;
  align-items: center;
  gap: 0.8125rem;
  padding: 0.5625rem 0;
  position: relative;
}
.act::before {
  content: '';
  position: absolute;
  left: 0.969rem;
  top: 50%;
  bottom: -0.5625rem;
  width: 1.5px;
  background: var(--border);
  z-index: 0;
}
.act.last-in-group::before {
  display: none;
}
.act-ico {
  width: 2rem;
  height: 2rem;
  border-radius: 50%;
  display: grid;
  place-items: center;
  flex-shrink: 0;
  z-index: 1;
}
.act-ico svg {
  width: 1rem;
  height: 1rem;
}
.act-ico.task {
  background: var(--blue-weak);
  color: var(--blue);
}
.act-ico.member {
  background: var(--green-weak);
  color: var(--green);
}
.act-ico.setting {
  background: var(--amber-weak);
  color: var(--amber);
}
.act-main {
  flex: 1;
  min-width: 0;
  display: flex;
  align-items: center;
  gap: 0.5rem;
}
.act-av {
  width: 1.375rem;
  height: 1.375rem;
  border-radius: 50%;
  display: grid;
  place-items: center;
  font-size: 0.625rem;
  font-weight: 700;
  color: #fff;
  flex-shrink: 0;
}
.act-text {
  font-size: 0.844rem;
  color: var(--text-2);
  line-height: 1.5;
}
.act-text :deep(b) {
  color: var(--text);
  font-weight: 600;
}
.act-text :deep(.tgt) {
  color: var(--accent);
  font-weight: 600;
  text-decoration: none;
}
.act-text :deep(.tgt:hover) {
  text-decoration: underline;
}
.act-text :deep(.st) {
  font-weight: 600;
}
.act-text :deep(.st.prog) {
  color: var(--blue);
}
.act-text :deep(.st.done) {
  color: var(--green);
}
.act-time {
  font-size: 0.75rem;
  color: var(--text-3);
  white-space: nowrap;
  flex-shrink: 0;
  margin-left: 0.75rem;
}

/* 로딩/빈 상태 */
.feed-state {
  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);
}
</style>
