<template>
  <div :style="styleMap?.mainStyle" class="relative w-full h-full box-border overflow-hidden">
    <ImageBg
      v-if="styleMap?.mainStyle?.imageSrc"
      :src="styleMap?.mainStyle?.imageSrc"
      :imageStyle="styleMap?.mainStyle?.imageStyle"
    />

    <div class="absolute left-0 top-0 overflow-hidden" :style="canvasStyle">
      <div class="relative overflow-hidden box-border" :style="scaledInnerStyle">
        <div
          v-if="showHeader"
          class="relative flex items-center justify-between"
          :style="headerStyle"
        >
          <ImageBg
            v-if="styleMap?.headerStyle?.imageSrc"
            :src="styleMap?.headerStyle?.imageSrc"
            :imageStyle="styleMap?.headerStyle?.imageStyle"
          />

          <template v-if="props.titleMode === 'arrow-buttons'">
            <button class="calendar-nav-btn" :style="navButtonStyle">
              <i
                class="lvgl-icon not-italic"
                v-html="getSymbol('LV_SYMBOL_LEFT')"
                :style="navIconStyle"
              ></i>
            </button>
            <div class="relative z-1 flex-1 text-center font-600" :style="headerTextStyle">
              {{ titleText }}
            </div>
            <button class="calendar-nav-btn" :style="navButtonStyle">
              <i
                class="lvgl-icon not-italic"
                v-html="getSymbol('LV_SYMBOL_RIGHT')"
                :style="navIconStyle"
              ></i>
            </button>
          </template>

          <template v-else>
            <div class="calendar-select-row relative z-1">
              <div class="calendar-select-box" :style="dropdownStyle">
                <span :style="headerTextStyle">{{ displayYear }}</span>
                <i
                  class="lvgl-icon not-italic"
                  v-html="getSymbol('LV_SYMBOL_DOWN')"
                  :style="dropdownArrowStyle"
                ></i>
              </div>
              <div class="calendar-select-box" :style="dropdownStyle">
                <span :style="headerTextStyle">{{ displayMonth }}</span>
                <i
                  class="lvgl-icon not-italic"
                  v-html="getSymbol('LV_SYMBOL_DOWN')"
                  :style="dropdownArrowStyle"
                ></i>
              </div>
            </div>
          </template>
        </div>

        <div class="calendar-body" :style="bodyStyle">
          <div class="calendar-weekdays">
            <div
              v-for="label in weekdayLabels"
              :key="label"
              class="calendar-weekday"
              :style="weekdayStyle"
            >
              {{ label }}
            </div>
          </div>

          <div class="calendar-grid">
            <div
              v-for="cell in calendarCells"
              :key="cell.key"
              class="calendar-cell relative box-border"
              :style="getCellStyle(cell)"
            >
              <ImageBg
                v-if="styleMap?.itemsStyle?.imageSrc"
                :src="styleMap?.itemsStyle?.imageSrc"
                :imageStyle="styleMap?.itemsStyle?.imageStyle"
              />
              <div class="relative z-1 flex h-full w-full flex-col items-center justify-center">
                <span :style="dayTextStyle(cell)">
                  {{ cell.day }}
                </span>
                <span v-if="props.showLunar" :style="lunarTextStyle(cell)">
                  {{ cell.lunarLabel }}
                </span>
              </div>
              <div v-if="cell.isCurrentDate" class="calendar-current-ring" />
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { computed, type CSSProperties } from 'vue'
import { useWidgetStyle } from '../hooks/useWidgetStyle'
import ImageBg from '../ImageBg.vue'
import { getSymbol } from '@/utils'
import {
  buildCalendarCells,
  formatTitle,
  getWeekdayLabels,
  resolveCurrentDate,
  resolveDisplayDate
} from './utils'

const BASE_WIDTH = 400
const BASE_HEIGHT = 320
const HEADER_HEIGHT = 56
const HORIZONTAL_PADDING = 12
const BODY_BOTTOM_PADDING = 12

const props = defineProps<{
  width: number
  height: number
  styles: any
  state?: string
  part?: string
  currentDate?: string
  displayDate?: string
  showLunar?: boolean
  titleMode?: 'none' | 'arrow-buttons' | 'drop-down'
}>()

const styleMap = useWidgetStyle({
  widget: 'lv_calendar',
  props
})

const weekdayLabels = getWeekdayLabels()

const showHeader = computed(() => props.titleMode !== 'none')

const contentPadding = computed(() => {
  const padding = String(styleMap.value?.mainStyle?.padding || '0px')
    .split(' ')
    .map((item) => Number.parseFloat(item) || 0)

  if (padding.length === 4) {
    return {
      top: padding[0],
      right: padding[1],
      bottom: padding[2],
      left: padding[3]
    }
  }

  return {
    top: 0,
    right: 0,
    bottom: 0,
    left: 0
  }
})

const canvasStyle = computed((): CSSProperties => {
  const { top, right, bottom, left } = contentPadding.value
  const availableWidth = Math.max(props.width - left - right, 0)
  const availableHeight = Math.max(props.height - top - bottom, 0)

  return {
    left: `${left}px`,
    top: `${top}px`,
    width: `${availableWidth}px`,
    height: `${availableHeight}px`
  }
})

const scaledInnerStyle = computed((): CSSProperties => {
  const width = Number.parseFloat(String(canvasStyle.value.width || 0)) || 0
  const height = Number.parseFloat(String(canvasStyle.value.height || 0)) || 0
  const scaleX = width / BASE_WIDTH || 0
  const scaleY = height / BASE_HEIGHT || 0

  return {
    width: `${BASE_WIDTH}px`,
    height: `${BASE_HEIGHT}px`,
    transform: `scale(${scaleX}, ${scaleY})`,
    transformOrigin: 'left top'
  }
})

const titleText = computed(() => formatTitle(props.displayDate, props.currentDate))

const displayValue = computed(() => {
  const currentDate = resolveCurrentDate(props.currentDate)
  return resolveDisplayDate(props.displayDate, currentDate)
})

const displayYear = computed(() => String(displayValue.value.year))
const displayMonth = computed(() => String(displayValue.value.month).padStart(2, '0'))

const calendarCells = computed(() => buildCalendarCells(props.displayDate, props.currentDate))

const headerStyle = computed((): CSSProperties => {
  return {
    ...styleMap.value?.headerStyle,
    height: `${HEADER_HEIGHT}px`,
    marginBottom: '8px',
    padding: '0 12px',
    boxSizing: 'border-box'
  }
})

const headerTextStyle = computed((): CSSProperties => {
  return {
    color: styleMap.value?.headerStyle?.color,
    fontSize: styleMap.value?.headerStyle?.fontSize,
    fontFamily: styleMap.value?.headerStyle?.fontFamily,
    fontStyle: styleMap.value?.headerStyle?.fontStyle,
    fontWeight: styleMap.value?.headerStyle?.fontWeight,
    textDecoration: styleMap.value?.headerStyle?.textDecoration,
    letterSpacing: styleMap.value?.headerStyle?.letterSpacing
  }
})

const navButtonStyle = computed((): CSSProperties => {
  return {
    width: '30px',
    height: '30px',
    borderRadius: '999px',
    border: 'none',
    background: '#2196f3',
    color: '#ffffff',
    padding: 0,
    display: 'flex',
    alignItems: 'center',
    justifyContent: 'center',
    position: 'relative',
    zIndex: 1
  }
})

const navIconStyle = computed((): CSSProperties => {
  return {
    fontSize: '12px',
    lineHeight: 1
  }
})

const dropdownStyle = computed((): CSSProperties => {
  return {
    minWidth: '132px',
    height: '34px',
    padding: '0 14px',
    borderRadius: '10px',
    border: '1px solid #dedede',
    backgroundColor: '#ffffff',
    display: 'flex',
    alignItems: 'center',
    justifyContent: 'space-between',
    boxSizing: 'border-box'
  }
})

const dropdownArrowStyle = computed((): CSSProperties => {
  return {
    color: styleMap.value?.headerStyle?.color,
    fontSize: '12px',
    lineHeight: 1,
    marginLeft: '12px'
  }
})

const bodyStyle = computed((): CSSProperties => {
  const topPadding = showHeader.value ? 0 : 10
  return {
    height: `${BASE_HEIGHT - (showHeader.value ? HEADER_HEIGHT + 8 : 0)}px`,
    padding: `${topPadding}px ${HORIZONTAL_PADDING}px ${BODY_BOTTOM_PADDING}px`,
    boxSizing: 'border-box'
  }
})

const weekdayStyle = computed((): CSSProperties => {
  return {
    ...headerTextStyle.value,
    fontWeight: 400,
    opacity: 0.6,
    textAlign: 'center'
  }
})

const itemGap = computed(() => {
  if (!props.showLunar) return 0
  const lineHeightValue = String(styleMap.value?.itemsStyle?.lineHeight || '')
  const parsedLineHeight = Number.parseFloat(lineHeightValue)
  const fontSize = Number.parseFloat(String(styleMap.value?.itemsStyle?.fontSize || 16)) || 16
  if (!parsedLineHeight) return 0
  return parsedLineHeight - fontSize * 1.2
})

const dayTextStyle = (cell: { inMonth: boolean }): CSSProperties => {
  return {
    color: styleMap.value?.itemsStyle?.color,
    fontSize: styleMap.value?.itemsStyle?.fontSize,
    fontFamily: styleMap.value?.itemsStyle?.fontFamily,
    fontStyle: styleMap.value?.itemsStyle?.fontStyle,
    fontWeight: styleMap.value?.itemsStyle?.fontWeight || 400,
    textDecoration: styleMap.value?.itemsStyle?.textDecoration,
    letterSpacing: styleMap.value?.itemsStyle?.letterSpacing,
    opacity: cell.inMonth ? 1 : 0.45,
    lineHeight: 1
  }
}

const lunarTextStyle = (cell: { inMonth: boolean }): CSSProperties => {
  return {
    ...dayTextStyle(cell),
    fontSize: '0.85em',
    // 默认-8在视觉是协调的
    marginTop: `${itemGap.value + 8}px`,
    whiteSpace: 'nowrap'
  }
}

const getCellStyle = (cell: { inMonth: boolean; isCurrentDate: boolean }): CSSProperties => {
  return {
    ...styleMap.value?.itemsStyle,
    display: 'flex',
    alignItems: 'center',
    justifyContent: 'center',
    boxSizing: 'border-box',
    position: 'relative',
    backgroundColor: styleMap.value?.itemsStyle?.backgroundColor,
    opacity: cell.inMonth ? 1 : 0.72
  }
}
</script>

<style scoped lang="less">
.calendar-body {
  display: flex;
  flex-direction: column;
}

.calendar-weekdays,
.calendar-grid {
  display: grid;
  grid-template-columns: repeat(7, minmax(0, 1fr));
}

.calendar-weekdays {
  margin-bottom: 10px;
}

.calendar-weekday {
  height: 30px;
  display: flex;
  align-items: center;
  justify-content: center;
}

.calendar-grid {
  grid-auto-rows: minmax(0, 1fr);
  gap: 8px;
  height: calc(100% - 40px);
}

.calendar-cell {
  min-height: 0;
}

.calendar-current-ring {
  position: absolute;
  inset: 0;
  border: 2px solid #2196f3;
  box-sizing: border-box;
  pointer-events: none;
}

.calendar-nav-btn {
  appearance: none;
  cursor: default;
}

.calendar-select-row {
  width: 100%;
  display: flex;
  align-items: center;
  gap: 14px;
}

.calendar-select-box {
  flex: 1 1 0;
}
</style>
