<script setup lang="ts">
import { ref, onMounted, watch, computed } from "vue";
import { commonStore } from "@/stores/commonStore";
import { storage } from "@/utils/storage.js";
import { ProjectService } from "@/components/service/project/projectService";
import { UserManagerService } from "@/components/service/management/UserManagerService";
import IconDeleteBtn from "@/components/atoms/button/IconDeleteBtn.vue";
import IconModifyBtn from "@/components/atoms/button/IconModifyBtn.vue";

/** ---------- 상수/상태 ---------- */
const store = commonStore();

const roleOptions = ["ROLE_USER", "ROLE_MODERATOR", "ROLE_ADMIN"] as const;

type SearchType = "전체" | "제목";
const searchOptions = [
  { label: "전체", value: "전체" as SearchType },
  { label: "이름", value: "제목" as SearchType },
];
const SEARCH_TYPE_MAP: Record<SearchType | "", "ALL" | "TITLE"> = {
  "": "ALL",
  전체: "ALL",
  제목: "TITLE",
};

const fmtDate = (v?: string) => (v ? v.replace("T", " ").slice(0, 19) : "-");
const splitCsv = (v?: string) =>
  String(v ?? "")
    .split(",")
    .map((s) => s.trim())
    .filter(Boolean);

/** 로그인한 사용자의 권한 (필요 시) */
const roles = ref<string[]>([]);
const refreshRoles = () => {
  const auth = storage.getAuth?.() ?? storage.get?.("vpp-Auth") ?? null;
  const r = auth?.userInfo?.roles ?? auth?.roles ?? [];
  roles.value = Array.isArray(r) ? r : [];
};
const isAdmin = computed(() => roles.value.includes("ROLE_ADMIN"));

/** 테이블 정의 */
const tableHeader = [
  { label: "No", width: "6%", style: "word-break: keep-all;" },
  { label: "Username", width: "10%", style: "word-break: keep-all;" },
  { label: "Email", width: "20%", style: "word-break: keep-all;" },
  { label: "Roles", width: "27%", style: "word-break: keep-all;" },
  { label: "Projects", width: "27%", style: "word-break: keep-all;" },
  { label: "Action", width: "10%", style: "word-break: keep-all;" },
];

const pageSizeOptions = [
  { text: "10 페이지", value: 10 },
  { text: "50 페이지", value: 50 },
  { text: "100 페이지", value: 100 },
];

/** ---------- 타입 ---------- */
type Row = {
  no: number;
  name: string; // username
  desc: string; // email
  users: string[]; // roles
  projects: string[]; // project names
  registDt: string;
  deviceKey: number; // user id
};

type SelectedUser = {
  id: number;
  username: string;
  email: string;
  role: string; // 단일
} | null;

/** ---------- 상태 ---------- */
const data = ref({
  params: {
    pageNum: 1,
    pageSize: 10,
    searchType: "전체" as SearchType,
    searchText: "",
  },
  results: [] as Row[],
  totalDataLength: 0,
  pageLength: 0,

  modalMode: "" as "create" | "edit" | "",
  selectedData: null as SelectedUser,

  allSelected: false,
  selected: [] as Array<{ deviceKey: number }>,

  isCreateVisible: false,
  isConfirmDialogVisible: false,
});

/** 사용자 폼: Roles 단일 선택 */
const userForm = ref({
  username: "",
  email: "",
  password: "",
  roles: "" as (typeof roleOptions)[number] | "", // 단일
});
const resetUserForm = () => {
  userForm.value = { username: "", email: "", password: "", roles: "" };
};

/** ---------- 목록/검색 ---------- */
function toRow(u: any, no: number, projectNames: string[] = []): Row {
  const rolesArr = Array.isArray(u?.roles)
    ? u.roles
    : typeof u?.roles === "string"
      ? splitCsv(u.roles)
      : [];

  return {
    no,
    name: u?.username ?? u?.name ?? "-",
    desc: u?.email ?? "-", // 이메일 우선
    users: rolesArr,
    projects: projectNames,
    registDt: fmtDate(u?.createdAt ?? u?.regDate),
    deviceKey: Number(u?.id),
  };
}

async function getData() {
  const { pageNum, pageSize, searchType, searchText } = data.value.params;
  const mapped = SEARCH_TYPE_MAP[searchType] || "ALL";
  const keyword = (searchText || "").trim().toLowerCase();

  try {
    // 1) 사용자 전체 조회
    const res = await UserManagerService.getAll();
    let list: any[] = Array.isArray(res?.data) ? res.data : [];

    // 2) 프론트 검색
    if (keyword) {
      list = list.filter((u) => {
        const username = String(u?.username ?? u?.name ?? "").toLowerCase();
        const email = String(u?.email ?? "").toLowerCase();
        const rolesStr = Array.isArray(u?.roles)
          ? u.roles.join(",").toLowerCase()
          : String(u?.roles ?? "").toLowerCase();

        if (mapped === "TITLE") return username.includes(keyword);
        return (
          username.includes(keyword) ||
          email.includes(keyword) ||
          rolesStr.includes(keyword)
        );
      });
    }

    // 3) 정렬 & 페이징
    list.sort((a, b) => (Number(b?.id) || 0) - (Number(a?.id) || 0));
    const totalElements = list.length;
    const totalPages = Math.max(1, Math.ceil(totalElements / pageSize));
    const safePage = Math.min(Math.max(1, pageNum), totalPages);
    const start = (safePage - 1) * pageSize;
    const pageSlice = list.slice(start, start + pageSize);
    const firstNo = totalElements - start;

    // 4) 프로젝트는 나중에 병렬로 가져와 반영
    data.value.results = pageSlice.map((u: any, i: number) =>
      toRow(u, Math.max(1, firstNo - i), []),
    );
    data.value.totalDataLength = totalElements;
    data.value.pageLength = totalPages;

    const projectLists = await Promise.all(
      pageSlice.map((u) =>
        ProjectService.userProjectAuthority(Number(u?.id))
          .then((r: any) => (Array.isArray(r?.data) ? r.data : []))
          .catch(() => []),
      ),
    );

    data.value.results = pageSlice.map((u: any, i: number) => {
      const projs = projectLists[i] || [];
      const names = projs
        .map((p: any) => String(p?.projectName ?? ""))
        .filter(Boolean);
      return toRow(u, Math.max(1, firstNo - i), names);
    });
  } catch (e) {
    console.error("[Users] fetch error:", e);
    data.value.results = [];
    data.value.totalDataLength = 0;
    data.value.pageLength = 1;
  }
}

/** ---------- 페이지/검색 트리거 ---------- */
function doSearch() {
  data.value.params.pageNum = 1;
  getData();
}
function changePageSize(size: number) {
  data.value.params.pageSize = size;
  data.value.params.pageNum = 1;
  getData();
}
function changePageNum(page: number) {
  data.value.params.pageNum = page;
  getData();
}
watch(
  () => data.value.params.searchType,
  () => doSearch(),
);

/** ---------- 모달 열기/닫기 (워크플로우 패턴) ---------- */
const openCreateModal = () => {
  data.value.selectedData = null;
  data.value.modalMode = "create";
  resetUserForm();
  data.value.isCreateVisible = true;
};

const openModifyModal = (row: Row) => {
  data.value.selectedData = {
    id: row.deviceKey,
    username: row.name,
    email: row.desc === "-" ? "" : row.desc,
    role: row.users?.[0] || "",
  };
  data.value.modalMode = "edit";

  // 프리필
  userForm.value.username = row.name || "";
  userForm.value.email = row.desc === "-" ? "" : row.desc || "";
  userForm.value.password = ""; // 수정 시 비워둠
  userForm.value.roles = (row.users?.[0] as any) || "";

  data.value.isCreateVisible = true;
};

const closeCreateModal = () => {
  data.value.isCreateVisible = false;
};

/** 모달 열림/닫힘 감시 → 닫힐 때 목록 갱신 */
watch(
  () => data.value.isCreateVisible,
  (now, prev) => {
    if (prev && !now) getData();
  },
);

/** ---------- 저장(생성/수정) ---------- */
async function saveUser() {
  try {
    const username = userForm.value.username.trim();
    const password = (userForm.value.password || "").trim();
    const email = (userForm.value.email || "").trim();
    const roleOne = userForm.value.roles || "";

    if (!username || (data.value.modalMode === "create" && !password)) {
      return store.setSnackbarMsg?.({
        color: "warning",
        text: "Username은 필수이며, 생성 시 Password도 필요합니다.",
        result: 400,
      });
    }

    const payload: any = {
      username,
      email,
      role: roleOne ? [roleOne] : undefined,
    };
    if (password) payload.password = password; // 수정 시 비워두면 미변경

    if (data.value.modalMode === "create") {
      await UserManagerService.signUp(payload);
      store.setSnackbarMsg?.({
        color: "success",
        text: "계정이 생성되었습니다.",
        result: 200,
      });
    } else {
      const id = Number(data.value.selectedData?.id);
      if (!id) {
        return store.setSnackbarMsg?.({
          color: "warning",
          text: "수정할 사용자 ID가 없습니다.",
          result: 400,
        });
      }
      // 서비스에 update(id, body) 메서드가 있어야 합니다.
      await UserManagerService.update(id, payload);
      store.setSnackbarMsg?.({
        color: "success",
        text: "수정되었습니다.",
        result: 200,
      });
    }

    await getData();
    data.value.isCreateVisible = false;
  } catch (e: any) {
    console.error("[User] save error:", e?.response?.data || e);
    store.setSnackbarMsg?.({
      color: "warning",
      text:
        e?.response?.data?.message || e?.response?.data?.error || "요청 실패",
      result: e?.response?.status || 500,
    });
  }
}

/** ---------- 삭제 ---------- */
function getSelectedAllData() {
  data.value.selected = data.value.allSelected
    ? data.value.results.map((r) => ({ deviceKey: r.deviceKey }))
    : [];
}

async function deleteRows(targetList?: Array<{ deviceKey: number }>) {
  const removeList = targetList ?? data.value.selected;
  if (!removeList?.length) return;

  const ids = removeList.map((x) => x.deviceKey);
  const remove = (id: number) =>
    UserManagerService.delete(id).then((res) => {
      if (res.status < 200 || res.status >= 300) return Promise.reject(res);
    });

  const after = async () => {
    if (
      ids.length >= data.value.results.length &&
      data.value.params.pageNum > 1
    ) {
      data.value.params.pageNum -= 1;
    }
    await getData();
    data.value.isConfirmDialogVisible = false;
    data.value.selected = [];
    data.value.allSelected = false;
  };

  if (ids.length === 1) {
    try {
      await remove(ids[0]);
      store.setSnackbarMsg?.({
        color: "success",
        text: "삭제되었습니다.",
        result: 200,
      });
    } catch (err) {
      store.setSnackbarMsg?.({
        color: "warning",
        text: "삭제 실패",
        result: 500,
      });
      console.error(err);
    } finally {
      after();
    }
  } else {
    Promise.all(ids.map(remove))
      .then(() =>
        store.setSnackbarMsg?.({
          color: "success",
          text: "모두 삭제되었습니다.",
          result: 200,
        }),
      )
      .catch((err) => {
        store.setSnackbarMsg?.({
          color: "warning",
          text: "일부 삭제 실패",
          result: 500,
        });
        console.error(err);
      })
      .finally(after);
  }
}

/** ---------- 마운트 ---------- */
onMounted(async () => {
  refreshRoles();
  await getData();
});
</script>

<template>
  <div class="w-100">
    <v-container fluid class="h-100 pa-5 d-flex flex-column align-center">
      <v-card
        flat
        class="bg-shades-transparent d-flex flex-column align-center justify-center w-100"
      >
        <!-- 헤더 -->
        <v-card flat class="bg-shades-transparent w-100">
          <v-card-item class="text-h5 font-weight-bold pt-0 pa-5 pl-0">
            <div class="d-flex flex-row justify-start align-center">
              <div>Users</div>
            </div>
          </v-card-item>
        </v-card>

        <!-- 검색/페이지 -->
        <v-card flat class="bg-shades-transparent w-100">
          <v-card flat class="bg-shades-transparent mb-4">
            <div class="d-flex justify-center flex-wrap align-center">
              <v-responsive
                max-width="180"
                min-width="180"
                class="mr-3 mt-3 mb-3"
              >
                <v-select
                  v-model="data.params.searchType"
                  label="검색조건"
                  density="compact"
                  :items="searchOptions"
                  item-title="label"
                  item-value="value"
                  hide-details
                />
              </v-responsive>

              <v-responsive min-width="540" max-width="540">
                <v-text-field
                  v-model="data.params.searchText"
                  label="검색어"
                  density="compact"
                  clearable
                  required
                  class="mt-3 mb-3"
                  hide-details
                  @keyup.enter="doSearch"
                />
              </v-responsive>

              <div class="ml-3">
                <v-btn
                  size="large"
                  color="primary"
                  :rounded="5"
                  @click="doSearch"
                >
                  <v-icon>mdi-magnify</v-icon>
                </v-btn>
              </div>
            </div>
          </v-card>

          <!-- 상단 툴바 -->
          <v-sheet
            class="bg-shades-transparent d-flex flex-wrap align-center mb-2"
          >
            <v-sheet class="d-flex flex-wrap me-auto bg-shades-transparent">
              <v-sheet
                class="d-flex align-center mr-3 mb-2 bg-shades-transparent"
              >
                <v-chip color="primary"
                  >총 {{ data.totalDataLength.toLocaleString() }}개</v-chip
                >
              </v-sheet>

              <v-sheet class="bg-shades-transparent">
                <v-responsive max-width="140" min-width="140" class="mb-2">
                  <v-select
                    v-model="data.params.pageSize"
                    density="compact"
                    :items="pageSizeOptions"
                    item-title="text"
                    item-value="value"
                    variant="outlined"
                    color="primary"
                    hide-details
                    @update:model-value="changePageSize"
                  />
                </v-responsive>
              </v-sheet>
            </v-sheet>

            <v-sheet class="justify-end mb-2">
              <v-btn color="info" @click="openCreateModal">Create User</v-btn>
            </v-sheet>
          </v-sheet>

          <!-- 테이블 -->
          <v-card class="rounded-lg pa-8">
            <v-col cols="12">
              <v-sheet>
                <v-table
                  density="comfortable"
                  fixed-header
                  height="625"
                  overflow-x-auto
                >
                  <colgroup>
                    <col style="width: 5%" />
                    <col
                      v-for="(item, i) in tableHeader"
                      :key="i"
                      :style="`width:${item.width}`"
                    />
                  </colgroup>

                  <thead>
                    <tr>
                      <th>
                        <v-checkbox
                          v-model="data.allSelected"
                          style="min-width: 36px"
                          :indeterminate="data.allSelected === true"
                          hide-details
                          @change="getSelectedAllData"
                        />
                      </th>
                      <th
                        v-for="(item, i) in tableHeader"
                        :key="i"
                        class="text-center font-weight-bold"
                        :style="`${item.style}`"
                      >
                        {{ item.label }}
                      </th>
                    </tr>
                  </thead>

                  <tbody class="text-body-2">
                    <tr
                      v-for="(item, i) in data.results"
                      :key="i"
                      class="text-center"
                    >
                      <td>
                        <v-checkbox
                          v-model="data.selected"
                          hide-details
                          :value="{ deviceKey: item.deviceKey }"
                        />
                      </td>

                      <td>{{ item.no }}</td>
                      <td>{{ item.name }}</td>

                      <td>
                        <div class="truncate-2">{{ item.desc || "-" }}</div>
                      </td>

                      <td>
                        <template v-if="item.users?.length">
                          <v-chip
                            v-for="u in item.users"
                            :key="u"
                            size="small"
                            class="ma-1"
                            color="blue-lighten-2"
                            text-color="white"
                          >
                            {{ u }}
                          </v-chip>
                        </template>
                        <span v-else>-</span>
                      </td>

                      <td>
                        <template v-if="item.projects?.length">
                          <v-chip
                            v-for="p in item.projects"
                            :key="p"
                            size="small"
                            class="ma-1"
                            color="purple-lighten-2"
                            text-color="white"
                          >
                            {{ p }}
                          </v-chip>
                        </template>
                        <span v-else>-</span>
                      </td>

                      <td style="white-space: nowrap">
                        <IconModifyBtn @on-click="openModifyModal(item)" />
                        <IconDeleteBtn
                          @on-click="
                            deleteRows([{ deviceKey: item.deviceKey }])
                          "
                        />
                      </td>
                    </tr>
                  </tbody>
                </v-table>
              </v-sheet>

              <v-card-actions class="text-center mt-8 justify-center">
                <v-pagination
                  v-model="data.params.pageNum"
                  :length="data.pageLength"
                  :total-visible="10"
                  color="primary"
                  rounded="circle"
                  @update:model-value="changePageNum"
                />
              </v-card-actions>
            </v-col>
          </v-card>
        </v-card>
      </v-card>
    </v-container>

    <!-- 생성/수정 모달 -->
    <v-dialog
      v-model="data.isCreateVisible"
      max-width="560"
      :persistent="false"
      :close-on-esc="true"
    >
      <v-card>
        <v-card-title class="headline">
          {{ data.modalMode === "create" ? "Create User" : "Modify User" }}
        </v-card-title>

        <v-card-text>
          <v-form>
            <v-text-field
              label="Username"
              v-model="userForm.username"
              :disabled="data.modalMode === 'edit'"
              required
            />
            <v-text-field
              label="Email"
              type="email"
              v-model="userForm.email"
              autocomplete="off"
            />
            <v-text-field
              label="Password"
              type="password"
              v-model="userForm.password"
              :required="data.modalMode === 'create'"
              autocomplete="new-password"
            />
            <v-select
              label="Roles"
              v-model="userForm.roles"
              :items="roleOptions"
              :multiple="false"
              clearable
              chips
            />
          </v-form>
        </v-card-text>

        <v-card-actions>
          <v-spacer />
          <v-btn color="primary" @click="saveUser">
            {{ data.modalMode === "create" ? "Create" : "Save" }}
          </v-btn>
          <v-btn text @click="closeCreateModal">Cancel</v-btn>
        </v-card-actions>
      </v-card>
    </v-dialog>
  </div>
</template>

<style scoped></style>
