<script setup lang="ts">
import IconDeleteBtn from "@/components/atoms/button/IconDeleteBtn.vue";
import IconInfoBtn from "@/components/atoms/button/IconInfoBtn.vue";
import { onMounted, ref } from "vue";
import { storage } from "@/utils/storage";
import ViewComponent from "@/components/templates/run/experiment/ViewComponent.vue";
import ExperimentCreateDialog from "@/components/atoms/organisms/ExperimentCreateDialog.vue";
import { ExperimentService } from "@/components/service/management/ExperimentService";
import { commonStore } from "@/stores/commonStore";
import { KubeflowRunService } from "@/components/service/management/KubeflowRunService";
import IconDownloadBtn from "@/components/atoms/button/IconDownloadBtn.vue";

const store = commonStore();

const openView = ref(false);
const execSelected = ref<any>(null);
const username = ref<string>("");

const tableHeader = [
  { label: "No", width: "5%", style: "word-break: keep-all;" },
  { label: "Execution Name", width: "20%", style: "word-break: keep-all;" },
  { label: "Status", width: "10%", style: "word-break: keep-all;" },
  { label: "Duration", width: "10%", style: "word-break: keep-all;" },
  { label: "Experiment", width: "15%", style: "word-break: keep-all;" },
  { label: "Workflow", width: "15%", style: "word-break: keep-all;" },
  { label: "Start Time", width: "15%", style: "word-break: keep-all;" },
  { label: "Registry Status", width: "10%", style: "word-break: keep-all;" },
  { label: "Action", width: "10%", style: "word-break: keep-all;" },
];

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

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

const data = ref({
  params: {
    pageNum: 1,
    pageSize: 10,
    searchType: "전체" as SearchType,
    searchText: "",
  },
  results: [] as any[],
  totalElements: 0,
  pageLength: 0,
  modalMode: "" as "create" | "edit" | "",
  selectedData: null as any,
  isCreateVisible: false,
});

function readUsernameFromStorage(): string {
  try {
    const raw =
      storage?.get?.("autoflow-auth") ??
      storage?.getAuth?.() ??
      localStorage.getItem("autoflow-auth") ??
      null;
    const auth = typeof raw === "string" ? JSON.parse(raw) : raw;
    const u1 = auth?.userInfo?.username;
    const u2 = auth?.username;
    const u3 = auth?.userInfo?.userName;
    const u4 = auth?.userInfo?.email?.split?.("@")?.[0];
    return (u1 || u2 || u3 || u4 || "").toString();
  } catch {
    return "";
  }
}
const getProjectId = (): number => {
  const v = Number(localStorage.getItem("projectId"));
  return Number.isFinite(v) ? v : 0;
};

const toRow = (r: any, idx: number) => {
  const fmtStart = (start?: string) => {
    if (!start) return "-";
    const d = new Date(start);
    if (isNaN(d.getTime())) return start;
    const yyyy = d.getFullYear();
    const MM = String(d.getMonth() + 1).padStart(2, "0");
    const dd = String(d.getDate()).padStart(2, "0");
    const hh = String(d.getHours()).padStart(2, "0");
    const mi = String(d.getMinutes()).padStart(2, "0");
    return `${yyyy}-${MM}-${dd} ${hh}:${mi}`;
  };

  const fmtDuration = (start?: string, end?: string) => {
    if (!start || !end) return "-";
    const ms = new Date(end).getTime() - new Date(start).getTime();
    if (!isFinite(ms) || ms < 0) return "-";
    const s = Math.floor(ms / 1000);
    const h = Math.floor(s / 3600);
    const m = Math.floor((s % 3600) / 60);
    const sec = s % 60;
    const pad = (n: number) => String(n).padStart(2, "0");
    return `${h}:${pad(m)}:${pad(sec)}`;
  };

  const toUiStatus = (state?: string) => {
    switch ((state || "").toUpperCase()) {
      case "SUCCEEDED":
        return "Succeeded";
      case "FAILED":
        return "Failed";
      case "RUNNING":
        return "Running";
      case "PENDING":
        return "Pending";
      case "SKIPPED":
        return "Skipped";
      default:
        return state || "-";
    }
  };

  const { pageNum, pageSize } = data.value.params;

  return {
    no: (pageNum - 1) * pageSize + (idx + 1),
    name: r.displayName ?? r.name ?? r.runId ?? "(no name)",
    status: toUiStatus(r.state),
    duration: fmtDuration(r.createdAt, r.finishedAt),
    experiment: r.experimentId ?? "-",
    workflow: r.pipelineId ?? r.pipelineVersionId ?? "-",
    startTime: fmtStart(r.createdAt),
    registryStatus: r.storageState ?? "-",
    run_id: r.runId,
    raw: r,
  };
};

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

  const payload = {
    projectId: getProjectId(),
    page: pageNum - 1, // 0-based
    size: pageSize,
    keyword,
    searchType: mapped,
    sortField: "createdAt",
    sortDirection: "DESC",
  };

  try {
    const res = await KubeflowRunService.search(payload as any);
    const result = res?.data ?? res;

    let list: any[] = [];
    let totalElements: number | undefined;
    let totalPages: number | undefined;
    let isServerPaged = false;

    if (Array.isArray(result)) list = result;
    else if (Array.isArray(result?.data)) list = result.data;
    else if (Array.isArray(result?.content)) {
      list = result.content;
      totalElements = result.totalElements;
      totalPages = result.totalPages;
      isServerPaged = true;
    } else if (Array.isArray(result?.runs)) list = result.runs;

    // 클라 보정 정렬 (서버 미적용 대비)
    list.sort((a, b) => {
      const ta = new Date(
        a.createdAt ||
          a.lastUpdateTime ||
          a.scheduledAt ||
          a.finishedAt ||
          a.startTime ||
          0,
      ).getTime();
      const tb = new Date(
        b.createdAt ||
          b.lastUpdateTime ||
          b.scheduledAt ||
          b.finishedAt ||
          b.startTime ||
          0,
      ).getTime();

      if (tb !== ta) return tb - ta; // 최신순
      const aid = a.id ?? a.runId ?? a.run_id ?? a.name ?? "";
      const bid = b.id ?? b.runId ?? b.run_id ?? b.name ?? "";
      return String(bid).localeCompare(String(aid)); // 안정화
    });

    if (!isServerPaged) {
      const total = list.length;
      const pages = Math.max(1, Math.ceil(total / pageSize));
      const safePage = Math.min(Math.max(1, pageNum), pages);
      const start = (safePage - 1) * pageSize;
      const slice = list.slice(start, start + pageSize);

      data.value.results = slice.map((r, i) => toRow(r, i));
      data.value.totalElements = total;
      data.value.pageLength = pages;
    } else {
      data.value.results = list.map((r, i) => toRow(r, i));
      data.value.totalElements =
        typeof totalElements === "number" ? totalElements : list.length;
      data.value.pageLength =
        typeof totalPages === "number"
          ? Math.max(1, totalPages)
          : Math.max(1, Math.ceil((data.value.totalElements || 0) / pageSize));
    }
  } catch (err) {
    console.error("[Executions] 조회 에러:", err);
    data.value.results = [];
    data.value.totalElements = 0;
    data.value.pageLength = 1;
  }
}

// 검색/페이지 조작
const doSearch = () => {
  data.value.params.pageNum = 1;
  fetchList();
};
const changePageNum = (page: number) => {
  data.value.params.pageNum = page;
  fetchList();
};
const changePageSize = (size: number) => {
  data.value.params.pageSize = size;
  data.value.params.pageNum = 1;
  fetchList();
};

// 삭제
const removeData = (value: Array<{ deviceKey: number }>) => {
  const ids = (value || []).map((x) => x.deviceKey);
  if (ids.length === 0) return;

  const removeOne = (id: number) =>
    ExperimentService.delete(id).then((res) => {
      if (res.status < 200 || res.status >= 300) return Promise.reject(res);
    });

  const after = () => {
    if (
      ids.length >= data.value.results.length &&
      data.value.params.pageNum > 1
    )
      data.value.params.pageNum -= 1;
    fetchList();
  };

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

// 상세 모달
const openInfoModal = (item: any) => {
  execSelected.value = item;
  openView.value = true;
};
function closeView() {
  openView.value = false;
}
const onSaved = () => fetchList();
const openCreateModal = () => {
  data.value.modalMode = "create";
  data.value.selectedData = {
    username: username.value,
    projectId: getProjectId(),
  };
  data.value.isCreateVisible = true;
};
const closeModal = () => {
  data.value.isCreateVisible = false;
  data.value.selectedData = null;
};

onMounted(() => {
  username.value = readUsernameFromStorage();
  fetchList();
});
</script>

<template>
  <div class="w-100" v-if="!openView">
    <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 class="text-primary">Executions</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.totalElements.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>

          <!-- 목록 -->
          <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
                      v-for="(item, i) in tableHeader"
                      :key="i"
                      :style="`width:${item.width}`"
                    />
                  </colgroup>
                  <thead>
                    <tr>
                      <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>{{ item.no }}</td>
                      <td class="text-truncate">{{ item.name }}</td>
                      <td>
                        <v-icon v-if="item.status === 'Succeeded'" color="green"
                          >mdi-check-circle</v-icon
                        >
                        <v-icon v-else-if="item.status === 'Failed'" color="red"
                          >mdi-close-circle</v-icon
                        >
                        <v-progress-circular
                          v-else-if="item.status === 'Running'"
                          indeterminate
                          size="18"
                          width="2"
                          color="info"
                        />

                        <v-icon
                          v-else-if="item.status === 'Pending'"
                          color="grey"
                          class="mdi-spin"
                        >
                          mdi-loading
                        </v-icon>

                        <!-- 그 외 -->
                        <v-icon v-else color="grey">mdi-help-circle</v-icon>
                      </td>
                      <td>{{ item.duration }}</td>
                      <td>{{ item.experiment }}</td>

                      <td>{{ item.workflow }}</td>
                      <td>{{ item.startTime }}</td>
                      <td>{{ item.registryStatus }}</td>
                      <td style="white-space: nowrap">
                        <IconInfoBtn @on-click="openInfoModal(item)" />
                        <IconDownloadBtn />
                        <IconDeleteBtn
                          @on-click="
                            removeData([
                              { deviceKey: item.raw?.id ?? item.run_id },
                            ])
                          "
                        />
                      </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="600" persistent>
      <ExperimentCreateDialog
        :edit-data="data.selectedData"
        :mode="data.modalMode"
        @close-modal="closeModal"
        @saved="onSaved"
        @handle-data="() => {}"
      />
    </v-dialog>
  </div>

  <div class="w-100" v-else>
    <ViewComponent
      v-if="openView"
      :experiment-info="execSelected"
      :onClose="closeView"
    />
  </div>
</template>

<style scoped></style>
