<script setup lang="ts">
import { ref, reactive, onMounted, computed } from 'vue'
import * as d3 from 'd3'

type barType = {
  label: string
  value: number
}

const props = defineProps({
  /**
   * 基準となる金額
   * @example 2000
   */
  standardAmount: { type: Number, default: 0 },
  /**
   * 比較する金額
   * @example 1000
   */
  comparisonAmount: { type: Number, default: 0 },
  /**
   * 基準となる金額のラベル
   * @example '請求額'
   */
  standardLabel: { type: String, default: '請求額' },
  /**
   * 比較する金額のラベル
   * @example '支払額'
   */
  comparisonLabel: { type: String, default: '支払額' },
  /**
   * 円グラフ内のラベル
   * @example '支払率'
   */
  pieChartLabel: { type: String, default: '支払率' },
  /**
   * グラフのメインカラー
   * @example '#00BBC9'
   */
  color: { type: String, default: '#00BBC9' },
})

/** 基準となる金額 */
const standardAmount = computed(() => props.standardAmount)
/** 比較する金額 */
const comparisonAmount = computed(() => props.comparisonAmount)

/** グラフを描写させるhtml要素 */
const chart = ref<HTMLElement | null>(null)
/** 比較する金額 ÷ 基準となる金額のレート */
const paymentRate = ref(
  standardAmount.value !== 0 ? (comparisonAmount.value / standardAmount.value) * 100 : 0
)
/** 円グラフに表示させるデータ */
const pieData = reactive([paymentRate.value, 100 - paymentRate.value])
/** 円グラフのサイズ */
const pieSize = reactive({ width: 90, height: 90 })
/** 円グラフのカラー */
const pieColor = d3
  .scaleOrdinal([props.color, '#D5D5D5'])
  .range(paymentRate.value > 100 ? ['#D20000', '#D5D5D5'] : [props.color, '#D5D5D5'])

/** 棒グラフに表示させるデータ */
const barData = reactive([
  {
    label: `${props.standardLabel}　${standardAmount.value.toLocaleString()}円`,
    value: standardAmount.value,
  },
  {
    label: `${props.comparisonLabel}　${comparisonAmount.value.toLocaleString()}円`,
    value: comparisonAmount.value,
  },
])
/** 棒グラフのサイズ */
const barSize = reactive({ width: 150, height: 90 })
/** 棒グラフのカラー */
const barColor = d3
  .scaleOrdinal(['#D5D5D5', props.color])
  .range(paymentRate.value > 100 ? ['#D5D5D5', '#D20000'] : ['#D5D5D5', props.color])

/** グラフを描写する関数 */
const chartCreate = () => {
  const svg = d3
    .select(chart.value)
    .append('svg')
    .attr('width', pieSize.width + barSize.width)
    .attr('height', Math.max(pieSize.height, barSize.height))
    .append('g')
    .attr('transform', 'translate(10, 0)')

  const pieGroup = svg
    .append('g')
    .attr('transform', `translate(${pieSize.width / 2 - 10},${pieSize.height / 2})`)
  const barGroup = svg.append('g').attr('transform', `translate(${pieSize.width}, 25)`)

  const pie = d3.pie().sort(null)
  const arc = d3
    .arc()
    .innerRadius(pieSize.width / 2 - 5)
    .outerRadius(pieSize.width / 2)

  pieGroup
    .selectAll('path')
    .data(pie(pieData))
    .enter()
    .append('path')
    .attr('d', arc)
    .attr('fill', (_: string[], i: number) => pieColor(i))

  pieGroup
    .append('text')
    .text(props.pieChartLabel)
    .attr('text-anchor', 'middle')
    .attr('dy', '-1.5em')
    .style('font-size', '12px')
    .style('fill', '#707070')

  pieGroup
    .append('text')
    .text(`${paymentRate.value.toFixed(0)}`)
    .attr('text-anchor', 'middle')
    .attr('dy', '0.4em')
    .style('font-size', '30px')
    .style('font-weight', 'bold')
    .style('fill', pieColor(0))

  pieGroup
    .append('text')
    .text('％')
    .attr('dy', '1.9em')
    .attr('dx', '0.5em')
    .style('font-size', '14px')
    .style('fill', '#707070')

  const xScale = d3
    .scaleLinear()
    .domain([0, d3.max(barData, (d: barType) => d.value)])
    .range([0, barSize.width - 10])

  barGroup
    .selectAll('rect')
    .data(barData)
    .enter()
    .append('rect')
    .attr('y', (_: barType, i: number) => i * 50)
    .attr('width', (d: barType) => xScale(d.value))
    .attr('height', '15px')
    .attr('fill', (_: barType, i: number) => barColor(i))

  barGroup
    .selectAll('text')
    .data(barData)
    .enter()
    .append('text')
    .text((d: barType) => d.label)
    .attr('y', (_: barType, i: number) => i * 50 + -10)
    .attr('dy', '4px')
    .style('font-size', '12px')
    .style('fill', '#333333')
}

onMounted(() => {
  chartCreate()
})
</script>

<template>
  <div style="width: fit-content" ref="chart"></div>
</template>

<style lang="sass" scoped></style>
