<template>
  <page-layout class="issue-detail-head">
    <d-skeleton :loading="loading && !issueData.title">
      <issue-description
        :key="issueDescKey"
        :title="issueData?.title"
        :created-time="issueData?.created_at"
        :closed-time="issueData?.closed_at"
        :user-name="issueData?.author?.name"
        :status-text="issueStat?.label"
        :statusIconColor="issueStat?.color"
        :statusBgColor="issueStat?.bgColor"
        :statusIcon="issueStat?.icon" :index-label="issueData?.iid + ''"
        :can-edit="isIssueAuthor || isDeveloper" @handle-save="updateTitle"
      />
      <template #placeholder>
        <div style="display: flex; gap: 0 16px;">
          <gc-skeleton-item style="width: 88px; height: 60px;"></gc-skeleton-item>
          <div style="flex: 1;">
            <gc-skeleton-item variant="square" style="height: 32px;"></gc-skeleton-item>
            <gc-skeleton-item style="width: 150px; height: 20px; margin-top: 8px;"></gc-skeleton-item>
          </div>
        </div>
      </template>
    </d-skeleton>

    <template #right>
      <div style="text-align: right;">
        <d-skeleton :loading="loading && !issueData.title">
          <d-button icon="add" variant="solid" class="search-bar-create"
            @click="$router.push({ name: 'repoIssueCreate' })" v-if="accountInfo?.username">
            新建 Issue
          </d-button>
          <template #placeholder>
            <gc-skeleton-item style="display: inline-block; width: 120px; height: 30px;"></gc-skeleton-item>
          </template>
        </d-skeleton>
      </div>
    </template>
  </page-layout>

  <page-layout class="issue-detail-main">
    <ScrollContainer @touch-bottom="onTouchBottom" :bottom="700" :finished="pageData.finished"
      :loading="pageData.loading">
      <d-skeleton :loading="loading && !issueData.title">
        <div class="g-content-card">
          <!-- issue 描述 -->
          <CommentDescription v-if="issueData?.id" :data="issueData" :author="issueData?.author" :user="accountInfo" @quote-reply="addQuoteReply" />

          <template v-for="item in pageData.commentlist" :key="item.id">
            <!-- 评论 -->
            <DiscussionItem
              v-if="item?.notes"
              :noteNum="item.notes.length"
              :author="item?.author || (item.notes && item.notes[0]?.author)"
              :user="accountInfo"
              :data="item.notes[0]"
              :created_at="item.created_at || item?.notes[0].created_at"
              :can-edit="item.notes[0]?.author.username === accountInfo.username"
              :noteId="item.id"
              :targetId="item?.notes[0].id"
              :repo-id="repoId"
              event-msg="评论："
              @delete="deleteCommentSelf(item)"
              @quote-reply="addQuoteReply"
            />
            <!-- issue event -->
            <EventItem
              v-else
              :author="item?.author"
              :event-msg="item.body"
              :create-time="item?.created_at"
              :eventType="item?.action"
            />
          </template>

        </div>
        <template #placeholder>
          <div style="display: flex;justify-content: space-between;gap: 0 16px;margin-bottom: 1em;">
            <gc-skeleton-item style="width: 200px; height: 16px;"></gc-skeleton-item>
            <gc-skeleton-item style="width: 100px; height: 16px;"></gc-skeleton-item>
          </div>
          <d-skeleton></d-skeleton>
          <template v-for="i in 2" :key="i">
            <div style="display: flex;justify-content: space-between;gap: 0 16px;margin-bottom: 1em;margin-top: 1em;">
              <gc-skeleton-item style="width: 200px; height: 16px;"></gc-skeleton-item>
              <gc-skeleton-item style="width: 100px; height: 16px;"></gc-skeleton-item>
            </div>
            <d-skeleton></d-skeleton>
          </template>
          <div style="display: flex;align-items: center; gap: 0 16px; margin-bottom: 1em;margin-top: 1em;">
            <gc-skeleton-item variant="circle" style="width: 40px; height: 40px;"></gc-skeleton-item>
            <gc-skeleton-item style="width: 50px; height: 30px;" v-for="i in 8" :key="i"></gc-skeleton-item>
          </div>
          <d-skeleton style="padding-left: 56px;"></d-skeleton>
        </template>
      </d-skeleton>

      <template v-if="pageData.loading && issueData.title">
        <template v-for="i in 1" :key="i">
          <div style="display: flex;justify-content: space-between;gap: 0 16px;margin-bottom: 1em;margin-top: 1em;">
            <gc-skeleton-item style="width: 200px; height: 16px;"></gc-skeleton-item>
            <gc-skeleton-item style="width: 100px; height: 16px;"></gc-skeleton-item>
          </div>
          <d-skeleton></d-skeleton>
        </template>
      </template>
      <!-- issue 添加评论 -->
      <section :class="{'mt-[24px]':true, 'edit-loading': pageData.loading }">
        <AddDiscussion
         @add-discussion="addDiscussion"
         @update-state="handleUpdateIssue"
         :loading="addIng" ref="RefAddDiscussion"
         :state="issueData?.state + ''"
         :updateDisabled="!(isDeveloper||isIssueAuthor)"
         :submit-disabled="!accountInfo.username"
        />
      </section>
    </ScrollContainer>

    <template #right>
      <d-skeleton :loading="loading && !issueData.title">
        <IssueAsideSetGroup v-model="issueData" :participants="participants" :project_id="issueData.project_id"
          :repoId="repoId" :issueId="$route.params.serialNumber"  />
        <template #placeholder>
          <div style="display: flex; flex-direction: column; gap: 16px 0;">
            <template v-for="i in 3" :key="i">
              <div style="display: flex;justify-content: space-between;gap: 0 16px;">
                <gc-skeleton-item style="flex: 1; height: 24px;"></gc-skeleton-item>
                <gc-skeleton-item style="width: 24px; height: 24px;"></gc-skeleton-item>
              </div>
              <d-skeleton :rows="1"></d-skeleton>
              <br />
            </template>
            <br />
            <gc-skeleton-item v-for="i in 3" :key="i" style="width: 150px; height: 16px;"></gc-skeleton-item>
          </div>
        </template>
      </d-skeleton>
    </template>
  </page-layout>
</template>

<script lang="ts" setup>
defineOptions({ name: 'IssueDetail' });
import { useRouter, useRoute } from 'vue-router';
import { ref, reactive, onMounted, watch, computed, onBeforeMount, nextTick, provide, type Ref } from 'vue';

import PageLayout from '@/components/PageLayout/index.vue';
import IssueDescription from '@/components/IssueDescription/index.vue';
import IssueAsideSetGroup from '@/views/Repo/components/IssueAsideSetGroup/index.vue';
import ScrollContainer from '@/components/ScrollContainer/index.vue';
import CommentDescription from './IssueDescription.vue';
import DiscussionItem from './DiscussionItem.vue';
import EventItem from './EventItem.vue';
import AddDiscussion from '@/views/Repo/components/AddDiscussion/index.vue';
import { Message } from 'vue-devui/message';

import { useAccountStore } from '@/stores/user';
import { useRepoId } from '@/utils/hooks/useRepoId';
import { reqCatch } from '@/utils/catch';
import { getRepoRole } from '@/api/repo/index';
import { repoInfoStore } from '@/stores/Repo/index';
import { issueStateOption } from '@/constant/issue';
import type { ISSUE_STATE } from '@/constant/issue';
import type { IIssue, INote, Idiscussions } from '@/api/issue/types';
import { useOrgId } from '@/utils/hooks/useOrgId';

import { fetchIssue, updateIssue, fetchIssueDiscussions, issueParticipants, createIssueDiscussions, updateIssueStat } from '@/api/issue';
import { promiseTimeout } from '@vueuse/core';

const { isAdmin, isDeveloper, isVisitor } = repoInfoStore();
const { orgId } = useOrgId('/');
const { repoId } = useRepoId();
const { accountInfo = {}} = useAccountStore();
const route = useRoute();
const loading = ref(false);

const addIng = ref(false);
const RefAddDiscussion = ref();
const roleData = ref({});
const issueDescKey = ref<number>(0);
const issueData: Ref<IIssue> = ref({});
const participants = ref([]); // 参与者
const pageData = reactive<{
  commentlist: Idiscussions | []; // 评论
  page_num: number;
  page_size: number;
  page_count: number;
  total: number;
  finished: boolean;
  loading: boolean;
  end_id?: number;
  end_system_id?: number;
}>({
  commentlist: [],
  page_count: 0,
  page_num: 1,
  page_size: 100,
  total: 0,
  finished: false,
  loading: false
});

const isIssueAuthor = computed(() => issueData.value.author?.username === accountInfo.username);

const issueStat = computed(() => ({
  label: issueStateOption[issueData.value?.state]?.label,
  color: issueStateOption[issueData.value?.state ]?.color,
  bgColor: issueStateOption[issueData.value?.state]?.bgColor,
  icon: issueStateOption[issueData.value?.state]?.icon
}));

onBeforeMount(() => {
  fetchIssueData();
  accountInfo?.username && fetchRole();
});

onMounted(async() => {
  fetchParticipants();
  await nextTick();
  fetchIssueCommentList();
});

const fetchRole = async() => {
  const res = await reqCatch(getRepoRole, { repoId: repoId.value });
  if (!res.error) {
    roleData.value = res.data.data;
  }
};

/**
 * issue 详情
 */
const fetchIssueData = async() => {
  loading.value = true;
  const res = await reqCatch(fetchIssue, {
    project_id: repoId.value,
    issue_iid: route.params.serialNumber
  });
  if (!res.error) {
    issueData.value = res.data.data;
    issueDescKey.value++;
  }
  loading.value = false;
};

/**
 * 参与者 列表
 */
const fetchParticipants = async() => {
  const res = await reqCatch(issueParticipants, {
    project_id: repoId.value,
    issue_iid: route.params.serialNumber
  });
  if (!res.error) {
    participants.value = res.data.data;
  }
};

/**
 *  获取评论列表
 *  @params {string} type 已经存在的数据
 */

const fetchIssueCommentList = async(type?: 'exist') => {
  pageData.loading = true;
  const res = await reqCatch(fetchIssueDiscussions, {
    issue_iid: route.params.serialNumber,
    project_id: repoId.value,
    type: 'user',
    page: pageData.page_num,
    per_page: pageData.page_size,
    end_id: pageData.end_id,
    end_system_id: pageData.end_system_id
  });

  if (!res.error) {
    const { content, page_count, page_num, total } = res.data.data;
    const { data = [], end_id, end_system_id } = content;

    if (type === 'exist') {
      // 获取重复分页，添加不存在的数据
      const newdata = data.filter(
        (item: Idiscussions) =>
          pageData.commentlist.findIndex(
            (value: Idiscussions) => value.id === item.id
          ) === -1
      );
      newdata.length > 0 && pageData.commentlist.push(...newdata);
    } else {
      // 添加数据
      pageData.commentlist.push(...data);
    }

    pageData.total = total;

    if (page_num >= page_count) {
      pageData.loading = false;
      pageData.finished = true;
    }

    pageData.end_id = end_id;
    pageData.end_system_id = end_system_id;
  }
  pageData.loading = false;
};

/**
 * 添加 评论
 */
const addDiscussion = async(obj:{body:string}) => {
  if (addIng.value) return;
  addIng.value = true;
  const res = await reqCatch(createIssueDiscussions, {
    project_id: repoId.value,
    issue_iid: issueData.value.iid,
    body: obj.body
  });
  addIng.value = false;
  if (!res.error) {
    pageData.commentlist.push(res.data.data);
    RefAddDiscussion.value.clear();
    if (!participants.value.some((e) => e?.username === accountInfo?.username)) {
    // 有新增评论者 更新参与者
      fetchParticipants();
    }
  }
};

/**
 * 删除评论
 */
const deleteCommentSelf = (item: object) => {
  const index = pageData.commentlist?.findIndex(e => e.id === item.id);
  if (index > -1) {
    pageData.commentlist.splice(index, 1);
  }
};

/**
 * 引用回复
 */
const addQuoteReply = (content:string) => {
  if (!content.startsWith('>')) {
    content = '> ' + content;
  }
  RefAddDiscussion.value.setBody(content + '\n\n');
};

/**
 * issue 状态切换
 */
const handleUpdateIssue = async(obj:any) => {
  const res = await reqCatch(updateIssueStat, {
    project_id: repoId.value,
    issue_iid: issueData.value.iid,
    discussion_locked: obj.discussion_locked,
    state_event: obj.state_event,
    discussions: obj.body
  });

  if (!res.error) {
    issueData.value = res.data.data;
    RefAddDiscussion.value.clear();
    updatePage();
  }
};

const updateStat = () => {
  fetchIssueData();
  updatePage();
};

/**
 * 修改 标题
 */
const updateTitle = async(title: string) => {
  if (!title) {
    Message.warning('标题不能为空！');
    return issueDescKey.value++;
  } else if (!/^.{1,200}$/.test(title)) {
    Message.warning('标题限制 1~200 个字符！');
    return issueDescKey.value++;
  } else if (issueData.value.title === title) {
    return issueDescKey.value++;
  }

  const res = await reqCatch(updateIssue, {
    project_id: issueData.value.project_id,
    issue_iid: issueData.value.iid,
    title }
  );

  if (!res.error) {
    issueData.value.title = res.data.data.title;
    issueData.value.canEdit = false;
    issueDescKey.value++;
    updateStat();
  }
};

/**
 * 触底加载更多
 */
const onTouchBottom = () => {
  if (pageData.loading || pageData.finished) return;
  pageData.page_num++;
};

/**
 * 有新增内容时重新获取
 */
const updatePage = () => {
  if (pageData.page_num * pageData.page_size > pageData.commentlist.length) {
    fetchIssueCommentList('exist');
  } else {
    pageData.page_num++;
  }
};

watch(() => pageData.page_num, () => {
  fetchIssueCommentList();
});

provide('roleData', roleData);
provide('repoId', repoId.value);
provide('issueId', route.params.serialNumber);
provide('isVisitor', isVisitor);
provide('isDeveloper', isDeveloper);
provide('isAdmin', isAdmin);
provide('isIssueAuthor', isIssueAuthor);
provide('updatePage', updatePage);
</script>

<style lang="scss" scoped>
.issue {
  &-detail-head {
    margin-top: 24px;
  }

  &-detail-main {
    margin-top: 24px;
    margin-bottom: 24px;
  }
}

@keyframes spin {
  0% {
    transform: rotate(0deg);
  }

  100% {
    transform: rotate(360deg);
  }
}

.loading {
  animation: spin 2s linear infinite;
  transform-origin: center center;
}

.loading-comment {
  display: flex;
  justify-content: center;
  align-items: center;
  line-height: 48px;
}

.add-btn-vertical-line {
  display: inline-block;
  width: 1px;
  height: 20px;
  background: #e6e7e8;
  margin-right: 10px;
  vertical-align: middle;
}

.edit-loading {
  position: relative;

  &::after {
    content: '';
    display: block;
    position: absolute;
    top: 0;
    bottom: 0;
    width: 100%;
    background-color: rgba($color: #fff, $alpha: 0.7);
    z-index: 99;
  }
}

</style>

