<script setup lang="ts">
import { onMounted, onBeforeUnmount, ref, computed } from "vue";
import { useRoute, useRouter } from "vue-router";
import { useAutoflowStore } from "@/stores/autoflowStore";

import type {
  UiProject,
  Permission,
} from "@/components/models/project/Project";
import { ProjectService } from "@/components/service/project/projectService";
import { UserManagerService } from "@/components/service/management/UserManagerService";
import { storage } from "@/utils/storage.js";

/** ===== 상수 & 기본 권한 ===== */
const DEFAULT_PERMISSIONS: Permission[] = [
  "CREATE",
  "READ",
  "UPDATE",
  "DELETE",
];

/** ===== 라우터 & 스토어 ===== */
const router = useRouter();
const route = useRoute();
const autoflowStore = useAutoflowStore();

/** ===== 상태 ===== */
const dialog = ref(false);
const contextMenu = ref(false);
const menuX = ref(0);
const menuY = ref(0);
const selectedIndex = ref<number | null>(null);

// id별 원본 등록자(reg) 보관 (값 그대로, 가공/문자열화 X)
const projectRegById = ref<Record<number, { regId?: string; regNm?: string }>>(
  {},
);

const projects = ref<UiProject[]>([]);
type UserOption = { id: number | string; username: string };
const userOptions = ref<UserOption[]>([]);
const modalMode = ref<"create" | "edit">("create");
const editingProjectId = ref<number | null>(null);

const form = ref({
  prjCd: "",
  prjNm: "",
  prjDesc: "",
  selectedUsers: [] as string[],
});
const roles = ref<string[]>([]);
const isAdmin = computed(() => roles.value.includes("ROLE_ADMIN"));
const currentUser = ref<{ id?: string | number; username?: string }>({});

const readAuth = () => {
  try {
    // 프로젝트에서 실제 쓰는 스토리지 키만 사용
    return (
      storage.getAuth?.() ??
      JSON.parse(localStorage.getItem("autoflow-auth") || "null")
    );
  } catch {
    return null;
  }
};

/** ===== 롤 ===== */

const refreshAuth = () => {
  const auth = readAuth();
  const r = auth?.userInfo?.roles ?? auth?.roles ?? [];
  roles.value = Array.isArray(r) ? r : [];
  currentUser.value = {
    id: auth?.userInfo?.id ?? auth?.id ?? auth?.userId,
    username: auth?.userInfo?.username ?? auth?.username ?? auth?.userName,
  };
};

const splitCSV = (v?: string) =>
  (v || "")
    .split(",")
    .map((s) => s.trim())
    .filter(Boolean);

const pickSelected = (p: ProjectSearchResponseItem) => {
  const modIds = splitCSV(p.modUserId);
  const modNms = splitCSV(p.modUserNm);
  const useMod = modIds.length > 0 || modNms.length > 0; // mod가 존재하면 mod 우선
  return {
    ids: useMod ? modIds : splitCSV(p.regUserId),
    nms: useMod ? modNms : splitCSV(p.regUserNm),
  };
};
// 열람 가능 여부 (등록/수정 사용자에 포함되면 OK)
const canViewProjectRaw = (p: ProjectSearchResponseItem) => {
  const idStr =
    currentUser.value.id != null ? String(currentUser.value.id).trim() : "";
  const uname = (currentUser.value.username ?? "").trim();

  const norm = (s: string) => s.trim().toLowerCase();
  const { ids, nms } = pickSelected(p);

  const allowIds = new Set(ids.map(String).map(norm));
  const allowNms = new Set(nms.map(norm));

  return (
    (idStr && allowIds.has(norm(idStr))) || (uname && allowNms.has(norm(uname)))
  );
};
/** ===== 페이지네이션 상태 ===== */
const pager = ref({ pageNum: 1, pageSize: 8, total: 0, pageLength: 1 });

const pagedProjects = computed(() => {
  const total = projects.value.length;
  pager.value.total = total;
  pager.value.pageLength = Math.max(1, Math.ceil(total / pager.value.pageSize));
  if (pager.value.pageNum > pager.value.pageLength)
    pager.value.pageNum = pager.value.pageLength;
  if (pager.value.pageNum < 1) pager.value.pageNum = 1;
  const start = (pager.value.pageNum - 1) * pager.value.pageSize;
  return projects.value.slice(start, start + pager.value.pageSize);
});

const changePageNum = (page: number) => {
  pager.value.pageNum = page;
};
const changePageSize = (size: number) => {
  pager.value.pageSize = size;
  pager.value.pageNum = 1;
};

/** ===== 서버 응답 타입 ===== */
interface ProjectSearchResponseItem {
  id: number;
  prjNm: string;
  prjDesc: string;
  prjStartDt?: string;
  regUserId?: string;
  regUserNm?: string;
  modUserId?: string;
  modUserNm?: string;
}
interface UserResponseItem {
  id: number | string;
  username: string;
}

/** ===== 페이로드 타입(서비스 시그니처를 못 바꾼다는 가정에서 지역 타입 분리) ===== */
// 생성 시 mod* 안 보냄
type NewProjectPayload = {
  id: null;
  prjCd: string;
  prjNm: string;
  prjDesc: string;
  prjStartDt: string;
  prjEndDt: string;
  delYn: string;
  regDate: string;
  regUserId?: string;
  regUserNm?: string;
};
// 수정 시 reg*는 기존 그대로 유지, mod*만 채움
type UpdateProjectPayload = {
  id: number;
  prjCd: string;
  prjNm: string;
  prjDesc: string;
  prjStartDt: string;
  prjEndDt: string;
  delYn: string;
  regDate: string;
  regUserId?: string;
  regUserNm?: string;
  modDate: string;
  modUserId?: string;
  modUserNm?: string;
};

/** ===== 유틸 ===== */
function buildCreatePayload(): NewProjectPayload {
  const today = new Date().toISOString().slice(0, 10);
  const nowIso = new Date().toISOString();

  const names = form.value.selectedUsers;
  const namesCsv = names.join(",");
  const idsCsv = names
    .map((name) => userOptions.value.find((u) => u.username === name)?.id)
    .filter(
      (v): v is number | string => v !== undefined && v !== null && v !== "",
    )
    .map(String)
    .join(","); // "6,5"

  // mod* 없음 (생성)
  return {
    id: null,
    prjCd: form.value.prjCd,
    prjNm: form.value.prjNm,
    prjDesc: form.value.prjDesc,
    prjStartDt: today,
    prjEndDt: today,
    delYn: "N",
    regDate: nowIso,
    regUserId: idsCsv,
    regUserNm: namesCsv,
  };
}

function buildUpdatePayload(): UpdateProjectPayload {
  const today = new Date().toISOString().slice(0, 10);
  const nowIso = new Date().toISOString();

  const names = form.value.selectedUsers;
  const namesCsv = names.join(",");
  const idsCsv = names
    .map((name) => userOptions.value.find((u) => u.username === name)?.id)
    .filter(
      (v): v is number | string => v !== undefined && v !== null && v !== "",
    )
    .map(String)
    .join(",");

  const id = editingProjectId.value!;
  const kept = projectRegById.value[id] || {};

  // reg*는 DB 원본 유지, mod*만 현재 선택으로 반영
  return {
    id,
    prjCd: form.value.prjCd,
    prjNm: form.value.prjNm,
    prjDesc: form.value.prjDesc,
    prjStartDt: today,
    prjEndDt: today,
    delYn: "N",
    regDate: nowIso,
    regUserId: kept.regId,
    regUserNm: kept.regNm,
    modDate: nowIso,
    modUserId: idsCsv,
    modUserNm: namesCsv,
  };
}

const fillerCount = computed(() =>
  Math.max(0, pager.value.pageSize - pagedProjects.value.length),
);
const fillers = computed(() => Array.from({ length: fillerCount.value }));

const resetForm = () => {
  form.value.prjCd = `PRJ${Date.now()}`;
  form.value.prjNm = "";
  form.value.prjDesc = "";
  form.value.selectedUsers = [];
};

const loadProjects = async () => {
  try {
    const { data } = await ProjectService.search();
    const rawList = data as ProjectSearchResponseItem[];

    const sorted = [...rawList].sort((a, b) => (b.id ?? 0) - (a.id ?? 0));

    // 🔐 현재 사용자 기준으로 필터
    const visible = sorted.filter(canViewProjectRaw);

    projectRegById.value = {};
    projects.value = visible.map((p) => {
      projectRegById.value[p.id] = { regId: p.regUserId, regNm: p.regUserNm };

      // 카드 표시용 사용자명: reg/mod 합쳐서 중복 제거
      const usersDisplay = pickSelected(p).nms.join(",");

      return {
        id: p.id,
        title: p.prjNm,
        creator: usersDisplay,
        date: p.prjStartDt,
        description: p.prjDesc,
      };
    });

    // 페이지 보정
    if (
      pager.value.pageNum >
      Math.max(1, Math.ceil(projects.value.length / pager.value.pageSize))
    ) {
      pager.value.pageNum = 1;
    }
  } catch (e) {
    console.error("프로젝트 조회 실패:", e);
  }
};

const loadUsers = async () => {
  try {
    const { data } = await UserManagerService.getAll();
    const raw = data as UserResponseItem[];
    userOptions.value = raw.map((u) => ({ id: u.id, username: u.username }));
  } catch (e) {
    console.error("사용자 조회 실패:", e);
  }
};

const openContextMenu = (event: MouseEvent, index: number) => {
  event.preventDefault();
  selectedIndex.value = index;
  menuX.value = event.pageX;
  menuY.value = event.pageY;
  contextMenu.value = true;
};

const closeDialog = () => {
  dialog.value = false;
  contextMenu.value = false;
  selectedIndex.value = null;
};

const selectProject = (index: number) => {
  const selected = pagedProjects.value[index];
  if (!selected) return;

  // 1) 가드가 즉시 읽도록 로컬스토리지에 먼저 기록
  localStorage.setItem("projectId", String(selected.id));
  localStorage.setItem("projectName", selected.title);

  // (스토어도 쓰고 있다면 같이 갱신)
  autoflowStore.setProjectId(selected.id);
  autoflowStore.setProjectName(selected.title);

  // 2) redirect 쿼리가 있으면 그리로, 없으면 /home
  const dest = (route.query.redirect as string) || "/home";
  router.replace(dest);
};
const grantDefaultPermissions = async (
  projectId: number,
  usernames: string[],
) => {
  if (!usernames?.length) return;
  const nameSet = new Set(usernames);
  const numericIds = userOptions.value
    .filter((u) => nameSet.has(u.username))
    .map((u) => Number(u.id))
    .filter((n) => Number.isFinite(n));
  await Promise.all(
    numericIds.map((uid) =>
      ProjectService.projectAuthority(projectId, {
        projectId,
        userId: uid,
        permissions: DEFAULT_PERMISSIONS,
      }),
    ),
  );
};

const saveProject = async () => {
  if (!isAdmin.value) {
    alert("권한이 없습니다. (ROLE_ADMIN 전용)");
    return;
  }
  try {
    let projectId: number;
    if (modalMode.value === "create") {
      const createPayload = buildCreatePayload();
      const createRes = await ProjectService.add(createPayload);
      projectId = createRes.data.id;
    } else {
      const updatePayload = buildUpdatePayload();
      await ProjectService.update(editingProjectId.value!, updatePayload);
      projectId = editingProjectId.value!;
    }
    await grantDefaultPermissions(projectId, form.value.selectedUsers);
    await loadProjects();
    closeDialog();
  } catch (error: any) {
    console.error(`${modalMode.value} 실패:`, error?.response?.data || error);
    alert(error?.response?.data?.message || "저장 실패");
  }
};

const deleteProject = async () => {
  try {
    if (selectedIndex.value === null) return;
    const target = pagedProjects.value[selectedIndex.value];
    await ProjectService.delete(target.id);
    await loadProjects();
  } catch (e: any) {
    console.error("삭제 실패:", e?.response?.status, e?.response?.data || e);
    alert("삭제 실패: " + (e?.response?.data?.message || e.message || ""));
  } finally {
    contextMenu.value = false;
  }
};

const onAddProject = () => {
  if (!isAdmin.value) {
    alert("권한이 없습니다. (ROLE_ADMIN 전용)");
    return;
  }
  modalMode.value = "create";
  editingProjectId.value = null;
  resetForm();
  dialog.value = true;
};

const modifyProject = () => {
  contextMenu.value = false;
  if (selectedIndex.value === null) return;
  const selected = pagedProjects.value[selectedIndex.value];

  modalMode.value = "edit";
  editingProjectId.value = selected.id;
  form.value.prjCd = selected.title;
  form.value.prjNm = selected.title;
  form.value.prjDesc = selected.description;

  // creator는 reg_user_nm 그대로 들어오므로 그대로 분해. 값 없으면 []
  form.value.selectedUsers =
    typeof selected.creator === "string" && selected.creator.length
      ? selected.creator.split(",").map((s) => s.trim())
      : [];

  dialog.value = true;
};

/** ===== 라이프사이클 ===== */
const onStorage = (e: StorageEvent) => {
  if (!e.key || /autoflow-auth/i.test(e.key)) {
    refreshAuth();
    loadProjects();
  }
};

onMounted(async () => {
  refreshAuth();
  await Promise.all([loadProjects(), loadUsers()]);
  window.addEventListener("storage", onStorage);
});

onBeforeUnmount(() => {
  window.removeEventListener("storage", onStorage);
});
</script>

<template>
  <v-container class="mt-12" style="max-width: 1600px">
    <v-row class="mb-6" align="center" justify="space-between">
      <v-col cols="auto">
        <h2 class="font-weight-bold text-h5">Project Selection</h2>
      </v-col>

      <v-col cols="auto">
        <v-btn
          v-show="isAdmin"
          color="secondary"
          variant="flat"
          class="text-white font-weight-bold"
          @click="onAddProject"
        >
          <v-icon left icon="mdi-plus" size="20" />
          Create Project
        </v-btn>
      </v-col>
    </v-row>

    <!-- 카드 그리드: 현재 페이지 데이터만 렌더 -->

    <v-row dense>
      <!-- 실제 카드 -->
      <v-col
        v-for="(project, index) in pagedProjects"
        :key="project.id"
        cols="12"
        sm="6"
        md="6"
        lg="6"
        class="d-flex"
      >
        <v-card
          class="project-card pa-4 flex-grow-1 d-flex flex-column"
          color="primary"
          variant="elevated"
          elevation="6"
          rounded="lg"
          @click="selectProject(index)"
          @contextmenu.prevent="(e) => openContextMenu(e, index)"
        >
          <v-card-title class="d-flex align-center">
            <v-icon color="#6EC1E4" icon="mdi-file" start size="18" />
            <h4>{{ project.title }}</h4>
          </v-card-title>

          <v-card-subtitle
            class="text-white text-caption d-flex justify-space-between"
          >
            <span>Select Users: {{ project.creator }}</span>
            <span>등록일: {{ project.date }}</span>
          </v-card-subtitle>

          <v-card-text
            class="text-white mt-3 text-body-2 flex-grow-1"
            style="white-space: normal"
          >
            {{ project.description }}
          </v-card-text>
        </v-card>
      </v-col>

      <!-- 플레이스홀더(보이지 않지만 자리 차지) -->
      <v-col
        v-for="(_, i) in fillers"
        :key="'filler-' + i"
        cols="12"
        sm="6"
        md="6"
        lg="6"
        class="d-flex"
      >
        <v-card
          class="project-card pa-4 flex-grow-1"
          style="visibility: hidden; pointer-events: none"
          rounded="lg"
        >
          &nbsp;
        </v-card>
      </v-col>
    </v-row>

    <!-- 하단 페이지네이션 영역 -->
    <v-row class="mt-6" align="center" justify="center">
      <v-col
        cols="12"
        class="d-flex justify-center align-center"
        style="gap: 16px"
      >
        <v-pagination
          v-model="pager.pageNum"
          :length="pager.pageLength"
          :total-visible="7"
          color="primary"
          rounded="circle"
          @update:model-value="changePageNum"
        />
      </v-col>
    </v-row>

    <!-- 컨텍스트 메뉴/다이얼로그 등 기존 그대로 -->
    <v-menu
      v-model="contextMenu"
      absolute
      :style="{ top: menuY + 'px', left: menuX + 'px' }"
      max-width="180"
      width="130"
    >
      <v-list>
        <v-list-item @click="modifyProject">
          <v-list-item-icon
            ><v-icon>mdi-square-edit-outline</v-icon></v-list-item-icon
          >
          <v-list-item-title>Modify</v-list-item-title>
        </v-list-item>
        <v-list-item @click="deleteProject">
          <v-list-item-icon><v-icon>mdi-delete</v-icon></v-list-item-icon>
          <v-list-item-title>Delete</v-list-item-title>
        </v-list-item>
      </v-list>
    </v-menu>

    <v-dialog v-model="dialog" max-width="500">
      <v-card>
        <v-card-title class="headline">
          {{ modalMode === "create" ? "Create Project" : "Modify Project" }}
        </v-card-title>

        <v-card-text>
          <v-form>
            <v-text-field label="Project Name" v-model="form.prjNm" required />
            <v-textarea
              label="Description"
              v-model="form.prjDesc"
              rows="3"
              required
            />
            <v-select
              label="Select Users"
              v-model="form.selectedUsers"
              :items="userOptions"
              item-title="username"
              item-value="username"
              multiple
              chips
              closable-chips
            />
          </v-form>
        </v-card-text>

        <v-card-actions>
          <v-spacer />
          <v-btn color="primary" @click="saveProject">
            {{ modalMode === "create" ? "Create" : "Save" }}
          </v-btn>
          <v-btn text @click="closeDialog">Cancel</v-btn>
        </v-card-actions>
      </v-card>
    </v-dialog>
  </v-container>
</template>

<style scoped>
.project-card {
  min-height: 140px;
}
</style>
