<script setup lang="ts">
import { computed } from "vue";

import type { ChartSeries } from "../api/market";

const props = defineProps<{ series: ChartSeries }>();
const width = 720;
const height = 260;
const inset = 18;
const values = computed(() => props.series.points.flatMap((point) => [point.high, point.low]));
const minimum = computed(() => Math.min(...values.value));
const maximum = computed(() => Math.max(...values.value));
const span = computed(() => Math.max(maximum.value - minimum.value, maximum.value * 0.01, 0.01));
const step = computed(() => (width - inset * 2) / Math.max(props.series.points.length, 1));
const candleWidth = computed(() => Math.max(2, Math.min(9, step.value * 0.58)));

function x(index: number): number {
  return inset + step.value * (index + 0.5);
}

function y(value: number): number {
  return inset + ((maximum.value - value) / span.value) * (height - inset * 2);
}

const linePath = computed(() =>
  props.series.points.map((point, index) => `${index ? "L" : "M"}${x(index)},${y(point.close)}`).join(" "),
);
const averagePath = computed(() =>
  props.series.points
    .filter((point) => point.average !== null)
    .map((point, index) => `${index ? "L" : "M"}${x(index)},${y(point.average ?? point.close)}`)
    .join(" "),
);
const zeroY = computed(() =>
  props.series.previous_close === null ? null : y(props.series.previous_close),
);
</script>

<template>
  <svg class="market-chart" :viewBox="`0 0 ${width} ${height}`" role="img" :aria-label="`${series.name}${series.interval === 'day' ? '日K' : '分时'}图`">
    <line v-if="series.interval === 'minute' && zeroY !== null" class="chart-zero" :x1="inset" :x2="width - inset" :y1="zeroY" :y2="zeroY" />
    <template v-if="series.interval === 'day'">
      <g v-for="(point, index) in series.points" :key="point.time" :class="point.close >= point.open ? 'candle-up' : 'candle-down'">
        <line :x1="x(index)" :x2="x(index)" :y1="y(point.high)" :y2="y(Math.max(point.open, point.close))" />
        <line :x1="x(index)" :x2="x(index)" :y1="y(Math.min(point.open, point.close))" :y2="y(point.low)" />
        <rect :x="x(index) - candleWidth / 2" :y="y(Math.max(point.open, point.close))" :width="candleWidth" :height="Math.max(1, Math.abs(y(point.open) - y(point.close)))" />
      </g>
    </template>
    <template v-else>
      <path class="chart-price" :d="linePath" />
      <path v-if="averagePath" class="chart-average" :d="averagePath" />
    </template>
  </svg>
</template>
