<template>
  <div class="process-overview-wrap">
    <AnalysisBox title="流程概要" :showAllBtn="false">
      <div class="main">
        <div class="left" :style="{ width: boardWidth + 'px' }">
          <div class="top">
            <div class="top-line" :style="{ width: lineWidth }">
              <div class="arrow-track">
                <div
                  class="arrow-segment arrow-segment-top"
                  v-for="i in mainArrowCount"
                  :key="`top-main-${i}`"
                ></div>
              </div>
              <div class="top-line1" ref="topLineEndRef">
                <div class="arrow-track">
                  <div
                    class="arrow-segment arrow-segment-top"
                    v-for="i in diagonalArrowCount"
                    :key="`top-diagonal-${i}`"
                  ></div>
                </div>
              </div>
            </div>
            <div class="start">
              <div class="icon">
                <img src="./assets/images/logo1.png" alt="" />
              </div>
              <div class="name">参议院</div>
            </div>
            <div class="content-box" :style="senateBoxStyle">
              <div
                class="item-box"
                v-for="slot in senateEventsPositioned"
                :key="slot.key"
                :style="{ left: slot.left + 'px', width: TIMELINE_ITEM_WIDTH_PX + 'px' }"
              >
                <div class="item-box-dot">
                  <img src="./assets/images/top-line-dot.png" alt="" />
                </div>
                <div class="item-content">
                  <div class="item-header">
                    <div class="item-title" :title="slot.item.actionTitle">
                      {{ slot.item.actionTitle }} <span v-if="slot.item.versionId">({{ slot.item.versionId }})</span>
                    </div>
                    <div class="item-header-icon" @click="handleClickDetail(true, slot.item, $event)">
                      <img src="./assets/images/item-header-icon.png" alt="" />
                    </div>
                  </div>
                  <div class="item-info" v-if="slot.item.agreeVote !== null || slot.item.disagreeVote !== null">
                    {{ formatVoteText(slot.item) }}
                  </div>
                  <div class="item-main" v-if="slot.item.fynrList && slot.item.fynrList.length">
                    <div
                      class="item-main-item"
                      v-for="(sub, subIndex) in slot.item.fynrList"
                      :key="`${slot.item.id}-${subIndex}-${sub}`"
                    >
                      <div class="icon"></div>
                      <CommonPrompt :content="sub">
                        <div class="text">{{ sub }}</div>
                      </CommonPrompt>
                    </div>
                  </div>
                </div>
                <div class="item-time">{{ slot.item.actionDate }}</div>
              </div>
            </div>
          </div>

          <div class="bottom">
            <div class="bottom-line" :style="{ width: lineWidth }">
              <div class="arrow-track">
                <div
                  class="arrow-segment arrow-segment-bottom"
                  v-for="i in mainArrowCount"
                  :key="`bottom-main-${i}`"
                ></div>
              </div>
              <div class="bottom-line1" ref="bottomLineEndRef">
                <div class="arrow-track">
                  <div
                    class="arrow-segment arrow-segment-bottom"
                    v-for="i in diagonalArrowCount"
                    :key="`bottom-diagonal-${i}`"
                  ></div>
                </div>
              </div>
            </div>
            <div class="start">
              <div class="name">众议院</div>
              <div class="icon">
                <img src="./assets/images/logo2.png" alt="" />
              </div>
            </div>
            <div class="content-box" :style="houseBoxStyle">
              <div
                class="item-box"
                v-for="slot in houseEventsPositioned"
                :key="slot.key"
                :style="{ left: slot.left + 'px', width: TIMELINE_ITEM_WIDTH_PX + 'px' }"
              >
                <div class="item-time">{{ slot.item.actionDate }}</div>
                <div class="item-box-dot">
                  <img src="./assets/images/bottom-line-dot.png" alt="" />
                </div>
                <div class="item-content">
                  <div class="item-header">
                    <div class="item-title" :title="slot.item.actionTitle">
                      {{ slot.item.actionTitle }} <span v-if="slot.item.versionId">({{ slot.item.versionId }})</span>
                    </div>
                    <div class="item-header-icon" @click="handleClickDetail(true, slot.item, $event)">
                      <img src="./assets/images/item-header-icon.png" alt="" />
                    </div>
                  </div>
                  <div class="item-info" v-if="slot.item.agreeVote !== null || slot.item.disagreeVote !== null">
                    {{ formatVoteText(slot.item) }}
                  </div>
                  <div class="item-main" v-if="slot.item.fynrList && slot.item.fynrList.length">
                    <div
                      class="item-main-item"
                      v-for="(sub, subIndex) in slot.item.fynrList"
                      :key="`${slot.item.id}-${subIndex}-${sub}`"
                    >
                      <div class="icon"></div>
                      <CommonPrompt :content="sub">
                        <div class="text">{{ sub }}</div>
                      </CommonPrompt>
                    </div>
                  </div>
                </div>
              </div>
            </div>
          </div>

          <div class="right" :style="{ left: rightPos, top: rightTop }">
            <div class="junction-dot">
              <div class="inner-dot"></div>
            </div>
            <div class="right-line" :style="{ width: sharedLineWidth + 'px' }">
              <div class="arrow-track">
                <div
                  class="arrow-segment arrow-segment-shared"
                  v-for="i in rightArrowCount"
                  :key="`right-${i}`"
                ></div>
              </div>
            </div>
          </div>

          <div class="shared-content-box" :style="sharedBoxStyle">
            <div
              class="item-box"
              v-for="item in sharedEvents"
              :key="`shared-${item.id}`"
              style="width: 280px; flex-shrink: 0;"
            >
              <div class="item-time">{{ item.actionDate }}</div>
              <div class="item-box-dot"></div>
              <div class="item-content">
                <div class="item-header">
                  <div class="item-title" :title="item.actionTitle">
                    {{ item.actionTitle }} <span v-if="item.versionId">({{ item.versionId }})</span>
                  </div>
                  <div class="item-header-icon" @click="handleClickDetail(true, item, $event)">
                    <img src="./assets/images/item-header-icon.png" alt="" />
                  </div>
                </div>
                <div class="item-info" v-if="item.agreeVote !== null || item.disagreeVote !== null">
                  {{ formatVoteText(item) }}
                </div>
                <div class="item-main" v-if="item.fynrList && item.fynrList.length">
                  <div
                    class="item-main-item"
                    v-for="(sub, subIndex) in item.fynrList"
                    :key="`shared-${item.id}-${subIndex}-${sub}`"
                  >
                    <div class="icon"></div>
                    <CommonPrompt :content="sub">
                      <div class="text">{{ sub }}</div>
                    </CommonPrompt>
                  </div>
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
    </AnalysisBox>

    <ProcessOverviewDetailDialog
      :visible="isShowDetailDialog"
      :detailItem="currentDetailItem"
      :position="dialogPos"
      @close="handleClickDetail(false)"
    />
  </div>
</template>

<script setup>
import { ref, onMounted, computed, nextTick } from "vue";
import { getBillDyqkSummary } from "@/api/bill";
import CommonPrompt from "../../commonPrompt/index.vue";
import ProcessOverviewDetailDialog from "../../ProcessOverviewDetailDialog.vue";

const actionList = ref([]);
const isShowDetailDialog = ref(false);
const currentDetailItem = ref({});
const dialogPos = ref({ left: "0px", top: "0px" });

const ORG_SENATE = "参议院";
const ORG_HOUSE = "众议院";
const PRESIDENT_KEYWORD = "呈递给总统";
const TIMELINE_ITEM_WIDTH_PX = 280;
const ARROW_SEGMENT_TOTAL_PX = 16;
const DIAGONAL_LINE_WIDTH_PX = 127;

const getBillDyqkSummaryList = async () => {
  try {
    const billId = window.sessionStorage.getItem("billId");
    if (!billId) {
      actionList.value = [];
      return;
    }
    const res = await getBillDyqkSummary({ id: billId });
    actionList.value = res && res.code === 200 && Array.isArray(res.data) ? res.data : [];
  } catch (error) {
    actionList.value = [];
  }
};

const getTime = (actionDate) => {
  const t = new Date(actionDate).getTime();
  return Number.isFinite(t) ? t : 0;
};

const isDualEvent = (item) => {
  const type = String(item?.congressType || "");
  return type.includes("双院");
};

const isSenateEvent = (item) => {
  const org = String(item?.orgName || "");
  const type = String(item?.congressType || "");
  return org === ORG_SENATE || type.includes(ORG_SENATE);
};

const isHouseEvent = (item) => {
  const org = String(item?.orgName || "");
  const type = String(item?.congressType || "");
  return org === ORG_HOUSE || type.includes(ORG_HOUSE);
};

const formatVoteText = (item) => {
  if (!item) return "";
  const agree = item.agreeVote ?? 0;
  const disagree = item.disagreeVote ?? 0;
  return `${agree}赞成：${disagree}反对`;
};

const sortedTimeline = computed(() => {
  return [...actionList.value].sort((a, b) => {
    const tA = getTime(a.actionDate);
    const tB = getTime(b.actionDate);
    if (tA !== tB) return tA - tB;
    return String(a.id ?? "").localeCompare(String(b.id ?? ""));
  });
});

const mergeIndexExclusive = computed(() => {
  if (!sortedTimeline.value.length) return 0;
  const idx = sortedTimeline.value.findIndex(
    (item) => item.actionTitle && item.actionTitle.includes(PRESIDENT_KEYWORD)
  );
  return idx >= 0 ? idx : sortedTimeline.value.length;
});

const dualLaneTimeline = computed(() => {
  return sortedTimeline.value
    .slice(0, mergeIndexExclusive.value)
    .filter((item) => !isDualEvent(item));
});

const senateEventsPositioned = computed(() => {
  const list = [];
  let slotIndex = 0;
  dualLaneTimeline.value.forEach((item) => {
    if (!isSenateEvent(item)) return;
    list.push({
      key: item.id,
      item,
      left: slotIndex * TIMELINE_ITEM_WIDTH_PX
    });
    slotIndex += 1;
  });
  return list;
});

const houseEventsPositioned = computed(() => {
  const list = [];
  let slotIndex = 0;
  dualLaneTimeline.value.forEach((item) => {
    if (!isHouseEvent(item)) return;
    list.push({
      key: item.id,
      item,
      left: slotIndex * TIMELINE_ITEM_WIDTH_PX
    });
    slotIndex += 1;
  });
  return list;
});

const sharedEvents = computed(() => {
  return sortedTimeline.value.filter((item, idx) => {
    return isDualEvent(item) || idx >= mergeIndexExclusive.value;
  });
});

const dualLaneCount = computed(() => {
  return Math.max(senateEventsPositioned.value.length, houseEventsPositioned.value.length);
});

const maxLineWidth = computed(() => {
  const senateWidth = 254 + dualLaneCount.value * TIMELINE_ITEM_WIDTH_PX;
  const houseWidth = 150 + dualLaneCount.value * TIMELINE_ITEM_WIDTH_PX;
  return Math.max(senateWidth, houseWidth);
});

const lineWidth = computed(() => `${maxLineWidth.value}px`);

const sharedLineWidth = computed(() => {
  const w = sharedEvents.value.length * TIMELINE_ITEM_WIDTH_PX;
  return Math.max(70, w);
});

const boardWidth = computed(() => {
  return maxLineWidth.value + 90 + 24 + sharedLineWidth.value + 180;
});

const mainArrowCount = computed(() => {
  return Math.max(1, Math.ceil(maxLineWidth.value / ARROW_SEGMENT_TOTAL_PX));
});

const diagonalArrowCount = computed(() => {
  return Math.max(1, Math.ceil(DIAGONAL_LINE_WIDTH_PX / ARROW_SEGMENT_TOTAL_PX));
});

const rightArrowCount = computed(() => {
  return Math.max(1, Math.ceil(sharedLineWidth.value / ARROW_SEGMENT_TOTAL_PX));
});

const senateBoxStyle = computed(() => ({
  width: `${maxLineWidth.value + 110 - 254}px`,
  justifyContent: "flex-start"
}));

const houseBoxStyle = computed(() => ({
  width: `${maxLineWidth.value + 110 - 150}px`,
  justifyContent: "flex-start"
}));

const rightPos = computed(() => `${maxLineWidth.value + 90}px`);

const sharedBoxStyle = computed(() => ({
  left: `${maxLineWidth.value + 219}px`,
  width: `${Math.max(sharedLineWidth.value, sharedEvents.value.length * TIMELINE_ITEM_WIDTH_PX)}px`
}));

const topLineEndRef = ref(null);
const bottomLineEndRef = ref(null);
const rightTop = ref("370px");

const handleClickDetail = (isShow, item = {}, event = null) => {
  isShowDetailDialog.value = isShow;
  if (!isShow) return;

  currentDetailItem.value = item;
  if (!event) return;

  const wrap = document.querySelector(".process-overview-wrap");
  if (!wrap) return;

  const rect = wrap.getBoundingClientRect();
  let left = event.clientX - rect.left + 20;
  let top = event.clientY - rect.top - 50;

  if (left + 480 > rect.width) {
    left = event.clientX - rect.left - 500;
  }

  dialogPos.value = { left: `${left}px`, top: `${top}px` };
};

onMounted(async () => {
  await getBillDyqkSummaryList();
  await nextTick();
  updateRightTop();
});

const updateRightTop = () => {
  const wrap = document.querySelector(".process-overview-wrap");
  if (!wrap) return;

  const topLineEndEl = topLineEndRef.value;
  const bottomLineEndEl = bottomLineEndRef.value;
  if (!topLineEndEl || !bottomLineEndEl) return;

  const wrapRect = wrap.getBoundingClientRect();
  const topRect = topLineEndEl.getBoundingClientRect();
  const bottomRect = bottomLineEndEl.getBoundingClientRect();

  const LINE_THICKNESS_PX = 8;
  const topLineCenterY = topRect.top + LINE_THICKNESS_PX / 2;
  const bottomLineCenterY = bottomRect.bottom - LINE_THICKNESS_PX / 2;

  const desiredCenterY = (topLineCenterY + bottomLineCenterY) / 2;
  rightTop.value = `${desiredCenterY - wrapRect.top - 12 - 49}px`;
};
</script>

<style lang="scss" scoped>
.process-overview-wrap {
  width: 1600px;
  height: 848px;
  margin-top: 16px;
  position: relative;

  .main {
    margin-left: 24px;
    margin-right: 24px;
    height: 790px;
    padding: 3px 10px 0px 10px;
    overflow-x: auto;
    overflow-y: hidden;

    &::-webkit-scrollbar {
      height: 8px;
    }

    &::-webkit-scrollbar-track {
      background: #f1f1f1;
      border-radius: 4px;
    }

    &::-webkit-scrollbar-thumb {
      background: rgba(20, 89, 187, 0.2);
      border-radius: 4px;

      &:hover {
        background: rgba(20, 89, 187, 0.4);
      }
    }

    .left {
      height: 680px;
      position: relative;
      display: flex;
      flex-direction: column;
      justify-content: center;
      min-width: fit-content;
      padding-right: 150px;

      .arrow-track {
        width: 100%;
        height: 8px;
        display: flex;
        align-items: center;
        overflow: hidden;
      }

      .arrow-segment {
        width: 14px;
        height: 8px;
        margin-right: 2px;
        flex-shrink: 0;
        clip-path: polygon(0 0, 80% 0, 100% 50%, 80% 100%, 0 100%, 14% 50%);
      }

      .arrow-segment-top {
        background: #3c8bf7;
      }

      .arrow-segment-bottom {
        background: #ffac4d;
      }

      .arrow-segment-shared {
        background: #5f656c;
      }

      .top {
        height: 260px;
        display: flex;
        position: relative;

        .top-line {
          position: absolute;
          left: 110px;
          top: 242px;
          height: 8px;

          .top-line1 {
            position: absolute;
            left: 100%;
            top: 0;
            height: 8px;
            width: 127px;
            transform: rotate(45deg);
            transform-origin: 0 0;
          }
        }

        .start {
          width: 120px;
          height: 260px;
          display: flex;
          flex-direction: column;
          justify-content: flex-end;
          align-items: center;

          .icon {
            width: 120px;
            height: 120px;

            img {
              width: 100%;
              height: 100%;
            }
          }

          .name {
            margin-top: 30px;
            width: 100px;
            height: 30px;
            display: flex;
            justify-content: center;
            align-items: center;
            padding: 1px 8px;
            box-sizing: border-box;
            border: 1px solid rgba(186, 224, 255, 1);
            border-radius: 4px;
            background: rgba(230, 244, 255, 1);
            color: rgba(22, 119, 255, 1);
            font-size: 16px;
            font-weight: 700;
          }
        }

        .content-box {
          position: relative;
          margin-left: 134px;
          margin-bottom: 19px;

          .item-box {
            position: absolute;
          }
        }
      }

      .bottom {
        margin-top: 150px;
        display: flex;
        position: relative;

        .bottom-line {
          position: absolute;
          left: 110px;
          top: 11px;
          height: 8px;

          .bottom-line1 {
            position: absolute;
            left: 100%;
            top: 0;
            height: 8px;
            width: 127px;
            transform: rotate(-45deg);
            transform-origin: 0 100%;
          }
        }

        .start {
          width: 120px;
          display: flex;
          flex-direction: column;
          justify-content: flex-start;
          align-items: center;

          .icon {
            margin-top: 30px;
            width: 120px;
            height: 120px;

            img {
              width: 100%;
              height: 100%;
            }
          }

          .name {
            width: 100px;
            height: 30px;
            display: flex;
            justify-content: center;
            align-items: center;
            padding: 1px 8px;
            box-sizing: border-box;
            border-radius: 4px;
            border: 1px solid rgba(255, 229, 143, 1);
            background: rgba(255, 251, 230, 1);
            color: rgba(250, 173, 20, 1);
            font-size: 16px;
            font-weight: 700;
          }
        }

        .content-box {
          position: relative;
          margin-left: 30px;

          .item-box {
            position: absolute;
          }
        }
      }

      .item-box {
        padding: 2px 15px;
        display: flex;
        flex-direction: column;
        position: relative;

        .item-time {
          position: absolute;
          left: 30px;
          height: 30px;
          color: rgba(95, 101, 108, 1);
          font-size: 16px;
          font-weight: 700;
          line-height: 30px;
        }

        .item-box-dot {
          position: absolute;
          z-index: 5;
          left: 10px;
          width: 12px;
          height: 12px;
          border-radius: 50%;
          background: #5f656c;
        }

        .item-content {
          border-left: 1px solid #919191;
        }

        .item-header {
          display: flex;
          align-items: center;
          height: 30px;
          padding: 0 10px;
          margin-bottom: 8px;

          .item-title {
            line-height: 26px;
            color: rgb(59, 65, 75);
            font-size: 20px;
            font-weight: 700;
            white-space: nowrap;
            overflow: hidden;
            text-overflow: ellipsis;

            span {
              color: rgba(132, 136, 142, 1);
              font-size: 14px;
              font-weight: 400;
            }
          }

          .item-header-icon {
            margin-left: 5px;
            width: 16px;
            height: 16px;
            cursor: pointer;
            flex-shrink: 0;

            img {
              width: 100%;
              height: 100%;
            }
          }
        }

        .item-info {
          padding: 0 10px;
          color: rgb(59, 65, 75);
          font-size: 16px;
          line-height: 24px;
          margin-bottom: 4px;
        }

        .item-main {
          padding: 5px 10px;

          .item-main-item {
            display: flex;
            align-items: baseline;
            width: 269px;
            margin-bottom: 4px;

            .icon {
              margin: 9px 12px;
              width: 6px;
              height: 6px;
              border-radius: 3px;
              background: #84888e;
            }

            .text {
              width: 240px;
              color: rgb(59, 65, 75);
              font-size: 16px;
              line-height: 24px;
              display: -webkit-box;
              line-clamp: 2;
              -webkit-line-clamp: 2;
              -webkit-box-orient: vertical;
              overflow: hidden;
              text-overflow: ellipsis;
              height: 48px;
            }

            :deep(.text-ellipsis) {
              white-space: normal !important;
            }
          }
        }
      }

      .top .item-box {
        justify-content: flex-end;

        .item-time {
          bottom: -50px;
          color: rgba(20, 89, 187, 1);
        }

        .item-box-dot {
          bottom: -7px;
          background: #1677ff;
        }

        .item-content {
          border-left: 1px solid rgb(20, 89, 187);
        }
      }

      .bottom .item-box {
        padding-top: 20px;
        justify-content: flex-start;

        .item-time {
          top: -30px;
          color: rgba(255, 172, 77, 1);
        }

        .item-box-dot {
          top: 7px;
          background: #faad14;
        }

        .item-content {
          border-left: 1px solid rgba(255, 172, 77, 1);
        }
      }

      .right {
        position: absolute;
        top: 370px;
        margin-left: 90px;
        display: flex;
        align-items: center;

        .junction-dot {
          width: 24px;
          height: 24px;
          border-radius: 50%;
          background: #5f656c;
          display: flex;
          justify-content: center;
          align-items: center;
          z-index: 10;
          margin-right: -4px;

          .inner-dot {
            width: 10px;
            height: 10px;
            border-radius: 50%;
            background: #fff;
          }
        }

        .right-line {
          height: 8px;
        }
      }

      .shared-content-box {
        position: absolute;
        top: 170px;
        display: flex;

        .item-box {
          justify-content: flex-end;

          .item-time {
            bottom: -50px;
          }

          .item-box-dot {
            bottom: -7px;
            background: #5f656c;
          }
        }
      }
    }
  }
}
</style>
