<script setup lang="ts">
import { computed, watchEffect } from 'vue'
import { CURVE_SIZE, NODE_BORDER_WIDTH } from './constants'
import { useGitContext } from './composables/useGitContext'
import { useTheme } from './composables/useTheme'
import { useScrollWindow } from './composables/useScrollWindow'
import { pxToRem } from './utils/units'
import { placeholderCommits } from './graph/placeholderData'

// ---------------------------------------------------------------------------
// Context
// ---------------------------------------------------------------------------

const {
  classes,
  showHeaders,
  rowHeight,
  headerRowHeight,
  nodeSize,
  graphColumnWidth,
  graphData,
  paging,
  setPaging,
  isIndexVisible,
  scrollBuffer,
} = useGitContext()

const { textColour, hoverColour, hoverTransitionDuration } = useTheme()

// ---------------------------------------------------------------------------
// Total commit count (for scroll spacer)
// ---------------------------------------------------------------------------

const totalCommitCount = computed(() => graphData.value.commits.length)

// ---------------------------------------------------------------------------
// Scroll window
// ---------------------------------------------------------------------------

const { startIndex, endIndex, scrollContainerRef } = useScrollWindow(
  totalCommitCount,
  rowHeight,
  scrollBuffer,
)

// Push scroll-driven paging into GitContext so all descendants can read it
watchEffect(() => {
  setPaging({
    startIndex: startIndex.value,
    endIndex: endIndex.value,
  })
})

// ---------------------------------------------------------------------------
// Spacer height (creates the scrollbar proportional to total commits)
// ---------------------------------------------------------------------------

const totalRowCount = computed(() =>
  totalCommitCount.value + (isIndexVisible.value ? 1 : 0),
)

const spacerHeight = computed(() =>
  `${totalRowCount.value * rowHeight.value}px`,
)

// ---------------------------------------------------------------------------
// Viewport offset — position the viewport at the correct scroll position
// ---------------------------------------------------------------------------

const viewportOffset = computed(() =>
  `${startIndex.value * rowHeight.value}px`,
)

// ---------------------------------------------------------------------------
// Visible commit count & rendered row count
// ---------------------------------------------------------------------------

const visibleCommitCount = computed(() => {
  const pagingValue = paging.value
  if (pagingValue) {
    return pagingValue.endIndex - pagingValue.startIndex
  }
  return graphData.value.commits.length
})

const commitRowCount = computed(() => {
  if (visibleCommitCount.value === 0) {
    return placeholderCommits.length
  }
  return visibleCommitCount.value + (isIndexVisible.value ? 1 : 0)
})

// ---------------------------------------------------------------------------
// CSS custom properties — cascade sizing values to all descendants
// ---------------------------------------------------------------------------

const cssVars = computed(() => ({
  '--git-log-row-height': pxToRem(rowHeight.value),
  '--git-log-header-row-height': pxToRem(headerRowHeight.value),
  '--git-log-node-size': pxToRem(nodeSize.value),
  '--git-log-graph-columns': graphData.value.graphColumns,
  '--git-log-graph-column-width': pxToRem(graphColumnWidth.value),
  '--git-log-graph-width': `calc(var(--git-log-graph-columns) * var(--git-log-graph-column-width))`,
  '--git-log-curve-size': pxToRem(CURVE_SIZE),
  '--git-log-node-border-width': pxToRem(NODE_BORDER_WIDTH),
  '--git-log-visible-commits': visibleCommitCount.value,
  '--git-log-commit-rows': commitRowCount.value,
  '--git-log-text-color': textColour.value,
  '--git-log-hover-color': hoverColour.value,
  '--git-log-hover-transition-duration': `${hoverTransitionDuration}s`,
}))
</script>

<template>
  <div
    :style="[classes?.containerStyles, cssVars]"
    :class="['container', classes?.containerClass]"
  >
    <!-- Scroll area -->
    <div ref="scrollContainerRef" class="scroll-area">
      <div
        class="viewport"
        :style="{ transform: `translateY(${viewportOffset})` }"
      >
        <div v-if="$slots.tags" class="tags">
          <div
            v-if="showHeaders"
            class="title"
          >
            Branch / Tag
          </div>

          <slot name="tags" />
        </div>

        <div v-if="$slots.graph" class="graph">
          <div
            v-if="showHeaders"
            class="title"
          >
            Graph
          </div>

          <slot name="graph" />
        </div>

        <div v-if="$slots.table" class="table">
          <slot name="table" />
        </div>
      </div>
      <div class="spacer" :style="{ height: spacerHeight }" />
    </div>
  </div>
</template>

<style scoped>
.container {
  position: relative;
  width: 100%;
  height: 100%;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

.scroll-area {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  position: relative;
}

.spacer {
  pointer-events: none;
}

.viewport {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  display: flex;
  will-change: transform;

  .tags, .graph {
      display: flex;
      flex-direction: column;
  }

  .tags {
    flex-grow: 0;
    flex-shrink: 0;
    width: 10rem;
      .title {
          margin-left: .5rem;
      }
  }

  .table {
    flex-grow: 1;
  }
}

.title {
  margin: 0;
  font-weight: 600;
  display: flex;
  flex-shrink: 0;
  align-items: center;
  height: var(--git-log-header-row-height);
  color: var(--git-log-text-color);
}
</style>
