<script setup lang="ts">
import { NButton, NH2, NText } from "naive-ui"
import { adminRejudge, getSubmissions, getTodaySubmissionCount } from "oj/api"
import {
  filterEmptyValue,
  parseTime,
  submissionMemoryFormat,
  submissionTimeFormat,
} from "utils/functions"
import { Submission } from "utils/types"
import Pagination from "~/shared/components/Pagination.vue"
import SubmissionResultTag from "~/shared/components/SubmissionResultTag.vue"
import { isDesktop } from "~/shared/composables/breakpoints"
import { useUserStore } from "~/shared/store/user"
import { LANGUAGE_SHOW_VALUE } from "~/utils/constants"
import { renderTableTitle } from "~/utils/renders"
import ButtonWithSearch from "./components/ButtonWithSearch.vue"
import StatisticsPanel from "./components/StatisticsPanel.vue"
import SubmissionLink from "./components/SubmissionLink.vue"
import SubmissionDetail from "./detail.vue"

interface Query {
  username: string
  result: string
  limit: number
  page: number
  myself: boolean
  problem: string
}

const route = useRoute()
const router = useRouter()
const userStore = useUserStore()
const message = useMessage()

const submissions = ref([])
const total = ref(0)
const todayCount = ref(0)
const query = reactive<Query>({
  result: <string>route.query.result ?? "",
  page: parseInt(<string>route.query.page) || 1,
  limit: parseInt(<string>route.query.limit) || 10,
  username: <string>route.query.username ?? "",
  myself: route.query.myself === "1",
  problem: <string>route.query.problem ?? "",
})
const submissionID = ref("")
const [statisticPanel, toggleStatisticPanel] = useToggle(false)
const [codePanel, toggleCodePanel] = useToggle(false)

const options: SelectOption[] = [
  { label: "全部", value: "" },
  { label: "答案正确", value: "0" },
  { label: "答案错误", value: "-1" },
  { label: "编译失败", value: "-2" },
  { label: "运行时错误", value: "4" },
]

async function listSubmissions() {
  query.result = <string>route.query.result ?? ""
  query.page = parseInt(<string>route.query.page) || 1
  query.limit = parseInt(<string>route.query.limit) || 10
  query.username = <string>route.query.username ?? ""
  query.myself = route.query.myself === "1"
  query.problem = <string>route.query.problem ?? ""

  if (query.page < 1) query.page = 1
  const offset = query.limit * (query.page - 1)
  const res = await getSubmissions({
    ...query,
    myself: query.myself ? "1" : "0",
    offset,
    problem_id: <string>route.query.problem ?? "",
    contest_id: <string>route.params.contestID ?? "",
  })
  submissions.value = res.data.results
  total.value = res.data.total
}

async function getTodayCount() {
  const res = await getTodaySubmissionCount()
  todayCount.value = res.data
}

onMounted(() => {
  listSubmissions()
  if (route.name === "submissions") {
    getTodayCount()
  }
})

function routerPush() {
  const newQuery = {
    ...query,
    myself: query.myself ? "1" : "0",
  }
  router.push({
    path: route.path,
    query: filterEmptyValue(newQuery),
  })
}

function search(username: string, problem: string) {
  query.username = username
  query.problem = problem
}

function clear() {
  query.username = ""
  query.myself = false
  query.result = ""
  query.problem = ""
}

async function rejudge(submissionID: string) {
  await adminRejudge(submissionID)
  message.success("重新判分成功")
  listSubmissions()
}

function problemClicked(row: Submission) {
  if (route.name === "contest submissions") {
    const path = router.resolve({
      name: "contest problem",
      params: {
        problemID: row.problem,
      },
    })
    window.open(path.href, "_blank")
  } else {
    window.open("/problem/" + row.problem, "_blank")
  }
}

function showCodePanel(id: string) {
  toggleCodePanel(true)
  submissionID.value = id
}

watch(() => query.page, routerPush)

watch(
  () => [query.limit, query.myself, query.result],
  () => {
    query.page = 1
    routerPush()
  },
)

watchDebounced(
  () => [query.username, query.problem],
  () => {
    query.page = 1
    routerPush()
  },
  { debounce: 500, maxWait: 1000 },
)

watch(
  () =>
    (route.name === "submissions" || route.name === "contest submissions") &&
    route.query,
  (newVal) => {
    if (newVal) listSubmissions()
  },
)

const columns = computed(() => {
  const res: DataTableColumn<Submission>[] = [
    {
      title: renderTableTitle("提交时间", "noto:seven-oclock"),
      key: "create_time",
      width: 200,
      render: (row) => parseTime(row.create_time, "YYYY-MM-DD HH:mm:ss"),
    },
    {
      title: renderTableTitle("提交编号", "fluent-emoji-flat:input-numbers"),
      key: "id",
      minWidth: 160,
      render: (row) =>
        h(SubmissionLink, {
          submission: row,
          onShowCode: () => showCodePanel(row.id),
        }),
    },
    {
      title: renderTableTitle("状态", "streamline-emojis:panda-face"),
      key: "status",
      width: 160,
      render: (row) => h(SubmissionResultTag, { result: row.result }),
    },
    {
      title: renderTableTitle("题目", "streamline-emojis:blossom"),
      key: "problem",
      width: 160,
      render: (row) =>
        h(
          ButtonWithSearch,
          {
            onClick: () => problemClicked(row),
            onSearch: () => (query.problem = row.problem),
          },
          () => row.problem,
        ),
    },
    {
      title: renderTableTitle("执行耗时", "streamline-emojis:snail"),
      key: "time",
      width: 120,
      align: "center",
      render: (row) => submissionTimeFormat(row.statistic_info.time_cost),
    },
    {
      title: renderTableTitle("占用内存", "streamline-emojis:bell"),
      key: "memory",
      width: 120,
      align: "center",
      render: (row) => submissionMemoryFormat(row.statistic_info.memory_cost),
    },
    {
      title: renderTableTitle(
        "语言",
        "streamline-emojis:globe-showing-europe-africa",
      ),
      key: "language",
      width: 120,
      render: (row) => LANGUAGE_SHOW_VALUE[row.language],
    },
    {
      title: renderTableTitle(
        "用户",
        "streamline-emojis:smiling-face-with-sunglasses",
      ),
      key: "username",
      minWidth: 160,
      render: (row) =>
        h(
          ButtonWithSearch,
          {
            onClick: () => window.open("/user?name=" + row.username, "_blank"),
            onSearch: () => (query.username = row.username),
          },
          () => row.username,
        ),
    },
  ]
  if (!route.params.contestID && userStore.isSuperAdmin) {
    res.push({
      title: renderTableTitle("选项", "streamline-emojis:wrench"),
      key: "rejudge",
      render: (row) =>
        h(
          NButton,
          {
            quaternary: true,
            size: "small",
            type: "primary",
            onClick: () => rejudge(row.id),
          },
          () => "重新判题",
        ),
    })
  }
  return res
})
</script>
<template>
  <n-flex vertical size="large">
    <n-space>
      <n-form :show-feedback="false" inline label-placement="left">
        <n-form-item label="提交状态">
          <n-select
            class="select"
            v-model:value="query.result"
            :options="options"
          />
        </n-form-item>
        <n-form-item v-if="userStore.isAuthed" label="只看自己">
          <n-switch v-model:value="query.myself" />
        </n-form-item>
      </n-form>
      <n-form :show-feedback="false" inline label-placement="left">
        <n-form-item>
          <n-input
            class="input"
            clearable
            v-model:value="query.username"
            placeholder="用户"
          />
        </n-form-item>
        <n-form-item>
          <n-input
            class="input"
            clearable
            v-model:value="query.problem"
            placeholder="题号"
          />
        </n-form-item>
      </n-form>
      <n-form :show-feedback="false" inline label-placement="left">
        <n-form-item>
          <n-button @click="search(query.username, query.problem)">
            搜索
          </n-button>
        </n-form-item>
        <n-form-item
          v-if="userStore.isSuperAdmin && route.name === 'submissions'"
        >
          <n-button @click="toggleStatisticPanel(true)">数据统计</n-button>
        </n-form-item>
        <n-form-item>
          <n-button @click="clear" quaternary>重置</n-button>
        </n-form-item>
        <n-form-item v-if="todayCount > 0">
          <component :is="isDesktop ? NH2 : NText" class="todayCount">
            <n-gradient-text>今日提交数：{{ todayCount }}</n-gradient-text>
          </component>
        </n-form-item>
      </n-form>
    </n-space>
    <n-data-table striped :columns="columns" :data="submissions" />
  </n-flex>
  <Pagination
    :total="total"
    v-model:limit="query.limit"
    v-model:page="query.page"
  />
  <n-modal
    v-if="userStore.isSuperAdmin"
    v-model:show="statisticPanel"
    preset="card"
    :style="{ maxWidth: isDesktop && '70vw', maxHeight: '80vh' }"
    :content-style="{ overflow: 'auto' }"
    title="提交记录的统计"
  >
    <StatisticsPanel :problem="query.problem" :username="query.username" />
  </n-modal>
  <n-modal
    v-model:show="codePanel"
    preset="card"
    :style="{ maxWidth: isDesktop && '70vw', maxHeight: '80vh' }"
    :content-style="{ overflow: 'auto' }"
    title="代码详情"
  >
    <SubmissionDetail :submissionID="submissionID" hideList />
  </n-modal>
</template>
<style scoped>
.select {
  width: 120px;
}

.input {
  width: 200px;
}

.code {
  font-size: 20px;
  overflow: auto;
}

.todayCount {
  margin: 0;
}
</style>
