<script setup lang="ts">
// 새 회의 만들기 — 공용 BaseModal 폼 모달(프로젝트 멤버 초대 모달과 동일 패턴).
// 참여 제한 멤버 선택은 업무 생성의 담당자 할당과 동일한 형태:
//   입력칸 고정 + 후보 드롭다운(focus 시) + 선택된 멤버는 입력칸 "아래"에 칩으로 표기.
import { computed, ref, watch } from 'vue'
import BaseModal from '@/components/common/BaseModal.vue'
import MeetingIcon from './MeetingIcon.vue'
import UserAvatar from '@/components/UserAvatar.vue'
import { useUser } from '@/composables/useUser'
import { useMeeting } from '@/composables/useMeeting'
import type { ApiMember } from '@/types/repo'
import type { ApiMeetingRoom } from '@/types/meeting'

interface Props {
  // 편집 모드 — 전달되면 해당 방의 현재 값으로 채우고 수정한다(없으면 생성 모드).
  editRoom?: ApiMeetingRoom | null
}
const props = defineProps<Props>()
const emit = defineEmits<{
  // 생성/수정 성공 → 부모가 목록 갱신 + 모달 닫기
  (e: 'created'): void
  (e: 'cancel'): void
}>()

const NAME_RE = /^[A-Za-z0-9가-힣ㄱ-ㅎㅏ-ㅣ_-]{1,64}$/

const userApi = useUser()
const meetingApi = useMeeting()

const isEdit = computed(() => !!props.editRoom)

// ISO(UTC) → datetime-local 입력값('YYYY-MM-DDTHH:mm', 로컬 시간)
function toLocalInput(iso: string): string {
  const d = new Date(iso)
  const pad = (n: number) => String(n).padStart(2, '0')
  return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}T${pad(d.getHours())}:${pad(d.getMinutes())}`
}

const name = ref(props.editRoom?.name ?? '')
const scheduledAt = ref(
  props.editRoom?.scheduledAt ? toLocalInput(props.editRoom.scheduledAt) : '',
)
const restrict = ref(props.editRoom?.restricted ?? false)
const error = ref('')
const submitting = ref(false)

// --- 참여 허용 멤버 선택 (업무 담당자 할당과 동일한 형태) ---
// 편집 모드면 현재 허용 멤버로 칩을 미리 채운다(백엔드가 진행자에게 allowedUsers 제공).
const selected = ref<ApiMember[]>([...(props.editRoom?.allowedUsers ?? [])]) // 선택된 멤버(입력칸 아래 칩)
const query = ref('')
const found = ref<ApiMember[]>([]) // 검색 결과
const showDropdown = ref(false)

// 검색어 변경 시 후보 갱신(서버 검색)
watch(query, async (q) => {
  if (!restrict.value) return
  found.value = await userApi.search(q)
})

// 아직 선택되지 않은 멤버 후보
const candidates = computed(() => {
  const picked = new Set(selected.value.map((u) => u.id))
  return found.value.filter((u) => !picked.has(u.id)).slice(0, 8)
})

async function onMemberFocus() {
  showDropdown.value = true
  if (found.value.length === 0) found.value = await userApi.search(query.value)
}
function onMemberBlur() {
  // 항목은 @mousedown.prevent 로 선택하므로 약간 지연 후 닫는다
  setTimeout(() => (showDropdown.value = false), 120)
}
function addMember(u: ApiMember) {
  if (!selected.value.some((x) => x.id === u.id)) selected.value.push(u)
  query.value = ''
  showDropdown.value = false
}
function removeMember(id: string) {
  selected.value = selected.value.filter((u) => u.id !== id)
}

async function submit() {
  if (submitting.value) return
  const n = name.value.trim()
  if (!NAME_RE.test(n)) {
    error.value = '방 이름은 한글·영문·숫자·-·_ 1~64자만 가능합니다.'
    return
  }
  // 이름은 표시용 라벨이라 중복을 허용한다(식별은 코드로). 별도 중복 검사 없음.
  error.value = ''
  submitting.value = true
  const payload = {
    name: n,
    scheduledAt: scheduledAt.value
      ? new Date(scheduledAt.value).toISOString()
      : undefined,
    allowedUserIds:
      restrict.value && selected.value.length
        ? selected.value.map((u) => u.id)
        : undefined,
  }
  try {
    if (props.editRoom) {
      await meetingApi.updateRoom(props.editRoom.id, payload)
    } else {
      await meetingApi.createRoom(payload)
    }
    emit('created')
  } catch {
    error.value = isEdit.value
      ? '방 수정에 실패했습니다. (이름이 이미 사용 중일 수 있습니다)'
      : '방 생성에 실패했습니다. (이름이 이미 사용 중일 수 있습니다)'
    submitting.value = false
  }
}
</script>

<template>
  <BaseModal
    :title="isEdit ? '회의 편집' : '새 회의 만들기'"
    @close="emit('cancel')"
  >
    <template #subtitle>
      {{ isEdit ? '내가 만든 방의 이름·예약·참여 제한을 수정합니다.' : '방을 만들면 내가 진행자가 됩니다.' }}
    </template>

    <form
      class="cf-form"
      @submit.prevent="submit"
    >
      <div class="form-field">
        <label class="form-label"><span class="req">*</span> 방 이름</label>
        <input
          v-model="name"
          class="form-input"
          autofocus
          placeholder="방 이름을 입력하세요"
          maxlength="64"
          @input="error = ''"
        >
      </div>

      <div class="form-field">
        <label class="form-label">예약 시각 <span class="opt">선택</span></label>
        <input
          v-model="scheduledAt"
          class="form-input"
          type="datetime-local"
        >
      </div>

      <div class="form-field">
        <label class="cf-toggle">
          <input
            v-model="restrict"
            type="checkbox"
          >
          <span class="cf-tg-box"><i v-if="restrict" /></span>
          <span class="cf-tg-txt"><b>참여 제한</b> — 지정한 멤버만 입장할 수 있습니다</span>
        </label>

        <div
          v-if="restrict"
          class="cf-picker"
        >
          <!-- 입력칸은 고정 — 선택된 멤버는 아래에 표기 -->
          <div class="combo">
            <div class="combo-field">
              <input
                v-model="query"
                class="combo-input"
                placeholder="멤버 검색…"
                autocomplete="off"
                @focus="onMemberFocus"
                @blur="onMemberBlur"
              >
              <span class="combo-caret">
                <svg
                  viewBox="0 0 24 24"
                  fill="none"
                  stroke="currentColor"
                  stroke-width="2"
                  stroke-linecap="round"
                  stroke-linejoin="round"
                ><path d="m6 9 6 6 6-6" /></svg>
              </span>
            </div>
            <!-- 멤버 후보 드롭다운 -->
            <div
              v-if="showDropdown"
              class="assignee-dd"
            >
              <button
                v-for="m in candidates"
                :key="m.id"
                type="button"
                class="assignee-dd-item"
                @mousedown.prevent="addMember(m)"
              >
                <span class="avatar"><UserAvatar
                  :url="m.avatarUrl"
                  :name="m.name"
                /></span>
                <span class="ad-nm">{{ m.name }}</span>
                <span class="ad-em">{{ m.email }}</span>
              </button>
              <div
                v-if="candidates.length === 0"
                class="assignee-dd-msg"
              >
                추가할 멤버가 없습니다.
              </div>
            </div>
          </div>
          <!-- 선택된 멤버 칩 (입력칸 아래에 추가) -->
          <div
            v-if="selected.length"
            class="assignee-chips"
          >
            <span
              v-for="a in selected"
              :key="a.id"
              class="chip"
            >
              <span class="avatar"><UserAvatar
                :url="a.avatarUrl"
                :name="a.name"
              /></span>
              {{ a.name }}
              <span
                class="x"
                @click="removeMember(a.id)"
              >×</span>
            </span>
          </div>
        </div>
      </div>

      <p
        v-if="error"
        class="cf-err"
      >
        <MeetingIcon name="warn" />{{ error }}
      </p>
    </form>

    <template #foot>
      <button
        type="button"
        class="mbtn"
        @click="emit('cancel')"
      >
        취소
      </button>
      <button
        type="button"
        class="mbtn primary"
        :disabled="submitting"
        @click="submit"
      >
        <MeetingIcon :name="isEdit ? 'edit' : 'plus'" />{{
          submitting
            ? isEdit
              ? '저장 중…'
              : '생성 중…'
            : isEdit
              ? '저장'
              : '방 만들기'
        }}
      </button>
    </template>
  </BaseModal>
</template>

<style scoped>
/* 폼은 BaseModal 본문(.bm-body)의 세로 간격을 그대로 상속받도록 display:contents */
.cf-form {
  display: contents;
}
.form-label .opt {
  font-weight: 500;
  color: var(--text-3);
}

/* 참여 제한 토글 */
.cf-toggle {
  display: flex;
  align-items: center;
  gap: 0.625rem;
  cursor: pointer;
  user-select: none;
}
.cf-toggle input {
  display: none;
}
.cf-tg-box {
  width: 1.125rem;
  height: 1.125rem;
  border: 0.09375rem solid var(--border-strong);
  border-radius: 0.3125rem;
  background: #fff;
  display: grid;
  place-items: center;
  flex-shrink: 0;
}
.cf-toggle input:checked + .cf-tg-box {
  background: var(--accent);
  border-color: var(--accent);
}
.cf-tg-box i {
  width: 0.5625rem;
  height: 0.5625rem;
  border-radius: 0.125rem;
  background: #fff;
}
.cf-tg-txt {
  font-size: 0.8125rem;
  color: var(--text-2);
}
.cf-tg-txt b {
  color: var(--text);
  font-weight: 600;
}

/* 멤버 피커 (업무 담당자 할당과 동일) */
.cf-picker {
  margin-top: 0.625rem;
}
.combo-field {
  border: 1px solid var(--border-strong);
  border-radius: var(--radius);
  padding: 0.4375rem 0.5rem;
  background: #fff;
  display: flex;
  align-items: center;
  gap: 0.375rem;
}
.combo-field:focus-within {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-weak);
}
.combo-input {
  flex: 1;
  min-width: 4.375rem;
  border: none;
  outline: none;
  font-family: inherit;
  font-size: 0.8125rem;
  padding: 0.25rem 0.125rem;
  background: transparent;
}
.combo-input::placeholder {
  color: var(--text-3);
}
.combo-caret {
  color: var(--text-3);
  display: grid;
  place-items: center;
  margin-left: auto;
  flex-shrink: 0;
}
.combo-caret svg {
  width: 1rem;
  height: 1rem;
}
/* 모달 안에서는 절대배치 시 스크롤 영역에 잘리므로 인라인(흐름 내)으로 펼친다 */
.assignee-dd {
  margin-top: 0.375rem;
  background: #fff;
  border: 1px solid var(--border);
  border-radius: 0.5625rem;
  box-shadow: var(--shadow-sm);
  padding: 0.375rem;
  max-height: 14rem;
  overflow-y: auto;
}
.assignee-dd-item {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  width: 100%;
  padding: 0.4375rem 0.5rem;
  border: none;
  background: transparent;
  border-radius: var(--radius-sm);
  cursor: pointer;
  font-family: inherit;
  text-align: left;
}
.assignee-dd-item:hover {
  background: #f5f6f8;
}
.assignee-dd-item .avatar {
  width: 1.5rem;
  height: 1.5rem;
  flex-shrink: 0;
}
.ad-nm {
  font-size: 0.8125rem;
  font-weight: 600;
  color: var(--text);
  white-space: nowrap;
}
.ad-em {
  font-size: 0.719rem;
  color: var(--text-3);
  margin-left: auto;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 9rem;
}
.assignee-dd-msg {
  padding: 0.625rem 0.5rem;
  font-size: 0.75rem;
  color: var(--text-3);
  text-align: center;
}
.assignee-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 0.375rem;
  margin-top: 0.5rem;
}
.chip {
  display: inline-flex;
  align-items: center;
  gap: 0.375rem;
  background: #f1f2f4;
  border: 1px solid var(--border);
  border-radius: 1.25rem;
  padding: 0.1875rem 0.5rem 0.1875rem 0.1875rem;
  font-size: 0.78125rem;
  font-weight: 600;
  color: var(--text);
  white-space: nowrap;
}
.chip .avatar {
  width: 1.375rem;
  height: 1.375rem;
  flex-shrink: 0;
}
.chip .x {
  color: var(--text-3);
  cursor: pointer;
  font-size: 0.8125rem;
  line-height: 1;
  margin-left: 0.0625rem;
}
.chip .x:hover {
  color: var(--red);
}
.cf-err {
  display: flex;
  align-items: center;
  gap: 0.4375rem;
  font-size: 0.78125rem;
  color: var(--red);
  font-weight: 500;
}
.cf-err svg {
  width: 0.9375rem;
  height: 0.9375rem;
  flex-shrink: 0;
}
</style>
