<script setup lang="ts">
import dayjs from 'dayjs'
import { IotRyDailyReportApi } from '@/api/pms/iotrydailyreport'
import { useDebounceFn } from '@vueuse/core'
import CountTo from '@/components/count-to1.vue'
import * as echarts from 'echarts'
import UnfilledReportDialog from '../UnfilledReportDialog.vue'

import { Motion, AnimatePresence } from 'motion-v'

import download from '@/utils/download'

interface Query {
  pageNo: number
  pageSize: number
  deptId: number
  contractName?: string
  taskName?: string
  createTime: string[]
  projectClassification: 1 | 2
}

const props = defineProps<{
  query: Query
  deptName: string
  refreshKey: number
}>()

const totalWorkKeys: [string, string, string, string, number][] = [
  ['constructionWells', '个', '累计施工井数', 'i-mdi:progress-wrench text-sky', 0],
  ['completedWells', '个', '累计完工井数', 'i-mdi:wrench-check-outline text-emerald', 0],
  [
    'utilizationRate',
    '%',
    '设备利用率',
    'i-material-symbols:check-circle-outline-rounded text-emerald',
    0
  ],
  [
    'totalPowerConsumption',
    'MWh',
    '累计用电量',
    'i-material-symbols:electric-bolt-outline-rounded text-sky',
    2
  ],
  [
    'totalFuelConsumption',
    '升',
    '累计油耗',
    'i-material-symbols:directions-car-outline-rounded text-sky',
    2
  ],
  [
    'averageFuelConsumption',
    '升',
    '平均油耗',
    'i-material-symbols:directions-car-outline-rounded text-sky',
    2
  ],
  ['totalCount', '个', '总数', 'i-tabler:report-analytics text-sky', 0],
  [
    'alreadyReported',
    '个',
    '已填报',
    'i-material-symbols:check-circle-outline-rounded text-emerald',
    0
  ],
  ['notReported', '个', '未填报', 'i-material-symbols:cancel-outline-rounded text-rose', 0]
]

const totalWork = ref({
  totalCount: 0,
  alreadyReported: 0,
  notReported: 0,
  totalFuelConsumption: 0,
  totalPowerConsumption: 0,
  constructionWells: 0,
  completedWells: 0,
  averageFuelConsumption: 0,
  utilizationRate: 0
})

const totalLoading = ref(false)

const getTotal = useDebounceFn(async () => {
  totalLoading.value = true

  const { pageNo, pageSize, ...other } = props.query

  try {
    let res1: any[]
    if (props.query.createTime && props.query.createTime.length === 2) {
      res1 = await IotRyDailyReportApi.ryDailyReportStatistics({
        createTime: props.query.createTime,
        projectClassification: props.query.projectClassification
      })

      totalWork.value.totalCount = res1[0].count
      totalWork.value.alreadyReported = res1[1].count
      totalWork.value.notReported = res1[2].count
    }

    const res2 = await IotRyDailyReportApi.totalWorkload(other)

    totalWork.value = {
      ...totalWork.value,
      constructionWells: 0,
      completedWells: 0,
      ...res2,
      totalPowerConsumption: (res2.totalPowerConsumption || 0) / 1000,
      totalFuelConsumption: res2.totalFuelConsumption || 0,
      averageFuelConsumption: res2.averageFuelConsumption || 0,
      utilizationRate: Number(((res2.utilizationRate || 0) * 100).toFixed(2))
    }
  } finally {
    totalLoading.value = false
  }
}, 1000)

interface List {
  id: number | null
  name: string | null
  type: '1' | '2' | '3'
  cumulativeGasInjection: number | null
  cumulativeWaterInjection: number | null
  cumulativePowerConsumption: number | null
  cumulativeFuelConsumption: number | null
  transitTime: number | null
  nonProductiveTime: number | null
  averageFuelConsumption: number | null
  utilizationRate: number | null
}

const list = ref<List[]>([])

const type = ref('2')

const columns = (type: string) => {
  return [
    {
      label: type === '2' ? '项目部' : '队伍',
      prop: 'name'
    },
    {
      label: '累计施工井数',
      prop: 'cumulativeConstructWells'
    },
    {
      label: '累计完工井数',
      prop: 'cumulativeCompletedWells'
    },
    {
      label: '累计用电量(MWh)',
      prop: 'cumulativePowerConsumption'
    },
    {
      label: '累计油耗(升)',
      prop: 'cumulativeFuelConsumption'
    },
    {
      label: '平均油耗(升)',
      prop: 'averageFuelConsumption'
    },
    {
      label: '平均时效(%)',
      prop: 'transitTime'
    },
    {
      label: '非生产时效(%)',
      prop: 'nonProductiveTime'
    },
    {
      label: '设备利用率(%)',
      prop: 'utilizationRate',
      action: true
    }
  ]
}

const listLoading = ref(false)

const formatter = (row: List, column: any) => {
  if (column.property === 'transitTime') {
    return (Number(row.transitTime ?? 0) * 100).toFixed(2) + '%'
  } else if (column.property === 'nonProductiveTime') {
    return (Number(row.nonProductiveTime ?? 0) * 100).toFixed(2) + '%'
  } else if (column.property === 'utilizationRate') {
    return (Number(row.utilizationRate ?? 0) * 100).toFixed(2) + '%'
  } else return row[column.property] ?? 0
}

const getList = useDebounceFn(async () => {
  listLoading.value = true
  try {
    const res = await IotRyDailyReportApi.getIotRyDailyReportSummary(props.query)

    const { list: reslist } = res

    type.value = reslist[0]?.type || '2'

    list.value = reslist.map(
      ({ id, projectDeptId, projectDeptName, teamId, teamName, sort, taskId, type, ...other }) => ({
        id: type === '2' ? projectDeptId : teamId,
        name: type === '2' ? projectDeptName : teamName,
        ...other,
        cumulativePowerConsumption: ((other.cumulativePowerConsumption || 0) / 1000).toFixed(2),
        cumulativeFuelConsumption: (other.cumulativeFuelConsumption || 0).toFixed(2),
        averageFuelConsumption: (other.averageFuelConsumption || 0).toFixed(2),
        utilizationRate: other.utilizationRate || 0
      })
    )
  } finally {
    listLoading.value = false
  }
}, 1000)

const tab = ref<'表格' | '看板'>('表格')

const currentTab = ref<'表格' | '看板'>('表格')

const direction = ref<'left' | 'right'>('right')

const handleSelectTab = (val: '表格' | '看板') => {
  tab.value = val
  direction.value = val === '看板' ? 'right' : 'left'
  nextTick(() => {
    currentTab.value = val
    setTimeout(() => {
      render()
    })
  })
}

const chartRef = ref<HTMLDivElement | null>(null)
let chart: echarts.ECharts | null = null
let chartContainerEl: HTMLDivElement | null = null

const xAxisData = ref<string[]>([])

const legend = ref<string[][]>([
  ['施工井数 (个)', 'cumulativeConstructWells'],
  ['完工井数 (个)', 'cumulativeCompletedWells'],
  // ['累计油耗 (万升)', 'cumulativeFuelConsumption'],
  ['油耗 (升)', 'cumulativeFuelConsumption'],
  // ['累计用电量 (MWh)', 'cumulativePowerConsumption'],
  ['用电量 (KWh)', 'cumulativePowerConsumption'],
  ['平均时效 (%)', 'transitTime'],
  ['设备利用率 (%)', 'utilizationRate']
])

const chartData = ref<Record<string, number[]>>({
  cumulativeFuelConsumption: [],
  cumulativeConstructWells: [],
  cumulativeCompletedWells: [],
  cumulativePowerConsumption: [],
  transitTime: [],
  utilizationRate: []
})

let chartLoading = ref(false)

const getChart = useDebounceFn(async () => {
  chartLoading.value = true

  try {
    const res = await IotRyDailyReportApi.getIotRyDailyReportSummaryPolyline(props.query)

    chartData.value = {
      cumulativeFuelConsumption: res.map((item) => item.cumulativeFuelConsumption || 0),
      // cumulativeFuelConsumption: res.map((item) => (item.cumulativeFuelConsumption || 0) / 10000),
      cumulativeConstructWells: res.map((item) => item.cumulativeConstructWells || 0),
      cumulativeCompletedWells: res.map((item) => item.cumulativeCompletedWells || 0),
      cumulativePowerConsumption: res.map((item) => item.cumulativePowerConsumption || 0),
      // cumulativePowerConsumption: res.map((item) => (item.cumulativePowerConsumption || 0) / 1000),
      transitTime: res.map((item) => (item.transitTime || 0) * 100),
      utilizationRate: res.map((item) => Number(((item.utilizationRate || 0) * 100).toFixed(2)))
    }

    xAxisData.value = res.map((item) => item.reportDate || '')
  } finally {
    chartLoading.value = false
  }
}, 1000)

const resizer = () => {
  chart?.resize()
}

onUnmounted(() => {
  window.removeEventListener('resize', resizer)
  chart?.dispose()
  chart = null
  chartContainerEl = null
})

const selectedLegends = ref<Record<string, boolean>>({})
const intervalArr = ref<number[]>([])
const maxInterval = ref(0)
const minInterval = ref(0)

const calcIntervals = () => {
  let maxVal = -Infinity
  let minVal = Infinity
  let hasData = false

  for (const [name, key] of legend.value) {
    if (selectedLegends.value[name] !== false) {
      const dataset = chartData.value[key] || []
      if (dataset.length > 0) {
        hasData = true
        for (const val of dataset) {
          if (val > maxVal) maxVal = val
          if (val < minVal) minVal = val
        }
      }
    }
  }

  if (!hasData) {
    maxVal = 10000
    minVal = 0
  } else {
    minVal = minVal > 0 ? 0 : minVal
  }

  const maxDigits = (Math.floor(maxVal) + '').length
  const minDigits = minVal === 0 ? 0 : (Math.floor(Math.abs(minVal)) + '').length
  const interval = Math.max(maxDigits, minDigits)

  maxInterval.value = interval
  minInterval.value = minDigits

  const arr = [0]
  for (let i = 1; i <= interval; i++) {
    arr.push(Math.pow(10, i))
  }
  intervalArr.value = arr
}

const mapDataValue = (value: number) => {
  if (value === 0) return 0

  const isPositive = value > 0
  const absItem = Math.abs(value)

  if (!intervalArr.value.length) return value

  const min_value = Math.max(...intervalArr.value.filter((v) => v <= absItem))
  const min_index = intervalArr.value.findIndex((v) => v === min_value)

  const denominator =
    min_index < intervalArr.value.length - 1
      ? intervalArr.value[min_index + 1] - intervalArr.value[min_index]
      : intervalArr.value[min_index] || 1

  const new_value = (absItem - min_value) / denominator + min_index

  return isPositive ? new_value : -new_value
}

const getSeries = () => {
  return legend.value.map(([name, key]) => ({
    name,
    type: 'line',
    smooth: true,
    showSymbol: true,
    data: chartData.value[key].map((value) => mapDataValue(value))
  }))
}

const initChart = () => {
  if (!chartRef.value) return

  if (chart && chartContainerEl === chartRef.value) {
    return
  }

  chart?.dispose()
  chart = echarts.init(chartRef.value, undefined, { renderer: 'canvas' })
  chartContainerEl = chartRef.value
  window.addEventListener('resize', resizer)

  chart.on('legendselectchanged', (params: any) => {
    selectedLegends.value = params.selected

    calcIntervals()

    chart?.setOption({
      yAxis: {
        min: -minInterval.value,
        max: maxInterval.value
      },
      series: getSeries()
    })
  })
}

const render = () => {
  if (!chartRef.value) return

  initChart()

  legend.value.forEach(([name]) => {
    selectedLegends.value[name] = true
  })

  calcIntervals()

  chart?.setOption(
    {
      tooltip: {
        trigger: 'axis',
        axisPointer: { type: 'line' },
        formatter: (params: any) => {
          let d = `${params[0].axisValueLabel}<br>`
          let item = params.map((el: any) => {
            const realValue = chartData.value[legend.value[el.componentIndex][1]][el.dataIndex]
            return `<div class="flex items-center justify-between mt-1 gap-1">
            <span>${el.marker} ${el.seriesName}</span>
            <span>${realValue.toFixed(2)} ${el.seriesName.split(' ')[1] || ''}</span>
          </div>`
          })
          return d + item.join('')
        }
      },
      legend: {
        data: legend.value.map(([name]) => name),
        selected: selectedLegends.value,
        show: true
      },
      xAxis: {
        type: 'category',
        data: xAxisData.value
      },
      yAxis: {
        type: 'value',
        min: -minInterval.value,
        max: maxInterval.value,
        interval: 1,
        axisLabel: {
          formatter: (v: number) => {
            const num = v === 0 ? 0 : v > 0 ? Math.pow(10, v) : -Math.pow(10, -v)
            return num.toLocaleString()
          }
        }
      },
      series: getSeries()
    },
    true
  )
}

const handleQuery = () => {
  getChart().then(() => {
    render()
  })
  getList()
  getTotal()
}

watch(
  () => [
    props.refreshKey,
    props.query.deptId,
    props.query.contractName,
    props.query.taskName,
    props.query.createTime?.[0],
    props.query.createTime?.[1],
    props.query.projectClassification
  ],
  () => {
    if (!props.query.createTime) {
      totalWork.value.totalCount = 0
      totalWork.value.notReported = 0
      totalWork.value.alreadyReported = 0
    }
    handleQuery()
  },
  { immediate: true }
)

const exportChart = () => {
  if (!chart) return
  let img = new Image()
  img.src = chart.getDataURL({
    type: 'png',
    pixelRatio: 1,
    backgroundColor: '#fff'
  })

  img.onload = function () {
    let canvas = document.createElement('canvas')
    canvas.width = img.width
    canvas.height = img.height
    let ctx = canvas.getContext('2d')
    ctx?.drawImage(img, 0, 0)
    let dataURL = canvas.toDataURL('image/png')

    let a = document.createElement('a')

    let event = new MouseEvent('click')

    a.href = dataURL
    a.download = `瑞鹰修井日报统计数据.png`
    a.dispatchEvent(event)
  }
}

const exportData = async () => {
  const res = await IotRyDailyReportApi.exportRyDailyReportStatistics(props.query)

  download.excel(res, '瑞鹰修井日报统计数据.xlsx')
}

const exportAll = async () => {
  if (tab.value === '看板') exportChart()
  else exportData()
}

const message = useMessage()

const unfilledDialogRef = ref()

const openUnfilledDialog = () => {
  // 检查是否选择了创建时间
  if (!props.query.createTime || props.query.createTime.length === 0) {
    message.warning('请先选择创建时间范围')
    return
  }

  // 打开弹窗
  unfilledDialogRef.value?.open()
}

const router = useRouter()

const tolist = (id: number) => {
  const { pageNo, pageSize, ...rest } = props.query

  router.push({
    name: 'IotRyXjDailyReport',
    query: {
      ...rest,
      deptId: id,
      projectClassification: 2
    }
  })
}
</script>

<template>
  <div class="grid grid-rows-[96px_1fr] gap-2 h-full min-h-0">
    <div class="grid grid-cols-9 gap-4">
      <div
        v-for="info in totalWorkKeys"
        :key="info[0]"
        class="bg-white dark:bg-[#1d1e1f] rounded-lg shadow px-1 py-2 flex flex-col items-center justify-center gap-0.5 min-w-0">
        <div class="size-6.5" :class="info[3]"></div>
        <count-to
          class="text-xl font-medium leading-6"
          :start-val="0"
          :end-val="totalWork[info[0]]"
          :decimals="info[4]"
          @click="info[2] === '未填报' ? openUnfilledDialog() : ''">
          <span class="text-xs leading-8 text-[var(--el-text-color-regular)]">暂无数据</span>
        </count-to>
        <div
          class="text-xs font-medium leading-5 text-[var(--el-text-color-regular)] whitespace-nowrap">
          {{ info[1] ? info[2] + '(' + info[1] + ')' : info[2] }}
        </div>
      </div>
    </div>

    <div class="bg-white dark:bg-[#1d1e1f] rounded-lg shadow flex flex-col p-3 gap-2 min-h-0">
      <div class="flex h-10 items-center justify-between">
        <el-button-group>
          <el-button
            size="default"
            :type="tab === '表格' ? 'primary' : 'default'"
            @click="handleSelectTab('表格')"
            >表格
          </el-button>
          <el-button
            size="default"
            :type="tab === '看板' ? 'primary' : 'default'"
            @click="handleSelectTab('看板')"
            >看板
          </el-button>
        </el-button-group>
        <h3 class="text-xl font-medium">{{ `${props.deptName}-${tab}` }}</h3>
        <el-button size="default" type="primary" @click="exportAll">导出</el-button>
      </div>
      <div class="flex-1 relative min-h-0">
        <el-auto-resizer class="absolute">
          <template #default="{ height }">
            <Motion
              as="div"
              :style="{ position: 'relative', overflow: 'hidden' }"
              :animate="{ height: `${height}px`, width: `100%` }"
              :transition="{ type: 'spring', stiffness: 200, damping: 25, duration: 0.3 }">
              <AnimatePresence :initial="false" mode="sync">
                <Motion
                  :key="currentTab"
                  as="div"
                  :initial="{ x: direction === 'left' ? '-100%' : '100%', opacity: 0 }"
                  :animate="{ x: '0%', opacity: 1 }"
                  :exit="{ x: direction === 'left' ? '50%' : '-50%', opacity: 0 }"
                  :transition="{ type: 'tween', stiffness: 300, damping: 30, duration: 0.3 }"
                  :style="{ position: 'absolute', left: 0, right: 0, top: 0 }">
                  <div :style="{ width: `100%`, height: `${height}px` }">
                    <zm-table
                      v-if="currentTab === '表格'"
                      :loading="listLoading"
                      :data="list"
                      :height="height"
                      show-border>
                      <template v-for="item in columns(type)" :key="item.prop">
                        <zm-table-column
                          v-if="item.prop !== 'name' && item.prop !== 'nonProductiveTime'"
                          :label="item.label"
                          :prop="item.prop"
                          :formatter="formatter"
                          :action="item.action" />
                        <zm-table-column
                          v-else-if="item.prop === 'name'"
                          :label="item.label"
                          :prop="item.prop">
                          <template #default="{ row }">
                            <el-button text type="primary" @click.prevent="tolist(row.id)">{{
                              row.name
                            }}</el-button>
                          </template>
                        </zm-table-column>
                        <zm-table-column v-else :label="item.label" :prop="item.prop">
                          <template #default="{ row }">
                            <el-button
                              v-if="row.nonProductiveTime > 0"
                              text
                              type="primary"
                              @click.prevent="tolist(row.id)">
                              {{ (Number(row.nonProductiveTime ?? 0) * 100).toFixed(2) + '%' }}
                            </el-button>
                            <span v-else>
                              {{ (Number(row.nonProductiveTime ?? 0) * 100).toFixed(2) + '%' }}
                            </span>
                          </template>
                        </zm-table-column>
                      </template>
                    </zm-table>
                    <div
                      ref="chartRef"
                      v-loading="chartLoading"
                      :key="dayjs().valueOf()"
                      v-else
                      :style="{ width: `100%`, height: `${height}px` }">
                    </div>
                  </div>
                </Motion>
              </AnimatePresence>
            </Motion>
          </template>
        </el-auto-resizer>
      </div>
    </div>
  </div>

  <UnfilledReportDialog ref="unfilledDialogRef" :query-params="props.query" />
</template>
