<script setup lang="ts">
import { ref, reactive, computed, onMounted, onUnmounted } from 'vue'
import { storeToRefs } from 'pinia'
import useUserStore from '@/store/modules/user'
import checkSuccessIcon from '@/static/image/check/checkSuccessIcon.png'
import { getTAttRecordItemDTO, checkRecordFlag, attCheck } from '@/api/clockIn'
import { parseTime } from '@/common/utils/ruoyi'
import { useDict } from '@/common/utils/dict'
import UserCard from '../../components/UserCard.vue'

const { att_status } = useDict('att_status')
const userStore = useUserStore()
const { userInfo } = storeToRefs(userStore)

// 状态管理
const classesData = ref<any>(null)
const currentTime = ref(parseTime(new Date(), '{h}:{i}:{s}'))
const scopeAddress = ref('')
const earlyMinute = ref('')
const layMinute = ref('')
const locationLoading = ref(false)
const retryCount = ref(0)
const maxRetryCount = 3
const locationError = ref(false)

const checkData = reactive({
  openState: false,
  type: 0,
  time: '',
  stateText: ''
})

const fixedPointList = ref<any[]>([])
const fixedPoint = reactive({
  latitude: 0,
  longitude: 0,
  radius: 0,
  addrName: ''
})

// 计算属性
const hasPlaces = computed(() => !!fixedPointList.value?.length)
const hasShift = computed(() => !!classesData.value?.recordItemDurations?.length)
const isDisabled = computed(() => !hasPlaces.value || !hasShift.value || !fixedPoint.latitude)
const isOutside = computed(() => !isDisabled.value && !inScope.value && fixedPoint.latitude)

const fixedPoints = computed(() => {
  return fixedPointList.value.filter(item => 
    isWithinRange(item.latitude, item.longitude, fixedPoint.latitude, fixedPoint.longitude, item.radius)
  )
})

const inScope = computed(() => fixedPoints.value?.length > 0)
const scopeStateText = computed(() => {
  if (!hasPlaces.value && !hasShift.value) return '暂无考勤点，暂无班次'
  if (!hasPlaces.value) return '暂无考勤点'
  if (!hasShift.value) return '暂无班次'
  return inScope.value ? '已进入考勤范围' : '不在考勤范围'
})

const stateText = computed(() => {
  return isDisabled.value ? '无法打卡' : isOutside.value ? '外勤打卡' : checkData.type === 1 ? '上班打卡' : checkData.type === 2 ? '下班打卡' : ''
})

// 生命周期
onMounted(async () => {
  getTAttRecordItemDTOEvent()
  getCheckRecordFlag()
  startTimeUpdate()
  
  // 页面加载时先检查定位权限和获取位置
  try {
    locationLoading.value = true
    await updatePosition()
    await checkAndRequestPermission()
  } catch (error) {
    console.error('页面初始化定位失败:', error)
  } finally {
    locationLoading.value = false
  }
})

onUnmounted(() => {
  clearInterval(timer)
})

let timer: number
function startTimeUpdate() {
  timer = setInterval(() => {
    currentTime.value = parseTime(new Date(), '{h}:{i}:{s}')
  }, 1000)
}

// 新增：权限检查和请求函数
async function checkAndRequestPermission() {
  try {
    const setting = await uni.getSetting();
    console.log('位置权限设置 uni.getSetting:', setting)
    
    if (!setting.authSetting['scope.userLocation']) {
      console.log('首次进入，位置权限未授权')
      // 自动触发授权请求
      const granted = await requestLocationPermission();
      if (granted) {
        console.log('用户已授权位置权限')
        return true
      } else {
        console.log('用户拒绝授权')
        return false
      }
    } else {
      console.log('位置权限已授权')
      return true
    }
  } catch (error) {
    console.error('检查权限失败:', error)
    return false
  }
}

// 独立的权限请求函数
function requestLocationPermission(): Promise<boolean> {
  return new Promise(resolve => {
    uni.showModal({
      title: '位置权限申请',
      content: '打卡需要获取您的位置信息，是否允许？',
      success: (modalRes) => {
        if (modalRes.confirm) {
          // 用户同意，申请权限
          uni.authorize({
            scope: 'scope.userLocation',
            success: () => {
              console.log('授权成功')
              resolve(true)
            },
            fail: (err) => {
              console.log('授权失败:', err)
              // 用户拒绝，引导去设置
              showPermissionGuide().then(() => {
                resolve(false)
              })
            }
          })
        } else {
          console.log('用户取消授权')
          resolve(false)
        }
      }
    })
  })
}

// 权限引导函数
function showPermissionGuide(): Promise<boolean> {
  return new Promise(resolve => {
    uni.showModal({
      title: '提示',
      content: '请在设置中开启位置权限',
      confirmText: '去设置',
      success: (res) => {
        if (res.confirm) {
          uni.openSetting({
            success: (settingRes) => {
              if (settingRes.authSetting['scope.userLocation']) {
                uni.showToast({ 
                  title: '已开启位置权限', 
                  icon: 'success' 
                })
                resolve(true)
              } else {
                uni.showToast({ 
                  title: '未开启位置权限', 
                  icon: 'none' 
                })
                resolve(false)
              }
            },
            fail: () => {
              resolve(false)
            }
          })
        } else {
          resolve(false)
        }
      }
    })
  })
}

// 错误处理函数
function handleLocationError(error: any) {
  if (error.errCode === 2 || error.errCode === 11) {
    uni.showToast({
      title: '获取位置失败，请检查定位是否开启',
      icon: 'none',
      duration: 3000
    })
  } else if (error.errCode === 1) {
    uni.showToast({
      title: '位置权限被拒绝，请授权后重试',
      icon: 'none',
      duration: 3000
    })
  } else if (error.errCode === 12) {
    uni.showToast({
      title: '网络异常，请检查网络连接',
      icon: 'none'
    })
  } else {
    uni.showToast({
      title: '获取位置失败，请重试',
      icon: 'none'
    })
  }
}

/* 封装的定位方法 */
async function updatePosition(retry = false) {
  try {
    locationLoading.value = true
    locationError.value = false
    
    if (retry && retryCount.value < maxRetryCount) {
      retryCount.value++
      uni.showToast({
        title: `第${retryCount.value}次重试定位...`,
        icon: 'none'
      })
    }
    
    const location = await safeGetLocation()
    if (!location) {
      if (retryCount.value < maxRetryCount && retry) {
        // 可以继续重试
        locationError.value = true
      } else {
        // 重试次数用完
        uni.showModal({
          title: '定位失败',
          content: '无法获取位置信息，请检查设备设置',
          showCancel: false
        })
      }
      return
    }
    
    // 成功获取位置
    retryCount.value = 0
    fixedPoint.latitude = location.latitude
    fixedPoint.longitude = location.longitude
    
    // 使用uni.chooseLocation作为逆地理编码的替代方案
    await getAddressFromLocation(location.latitude, location.longitude)
    
    checkInScopeStatus()
    
  } catch (error) {
    console.error('定位更新失败:', error)
    locationError.value = true
  } finally {
    locationLoading.value = false
  }
}

async function safeGetLocation(): Promise<{latitude: number; longitude: number} | null> {
  return new Promise(async (resolve) => {
    try {
      // 1. 先尝试获取位置
      const location = await uni.getLocation({
        type: 'gcj02',
        isHighAccuracy: true
      });
      
      console.log('获取位置成功:', location);
      resolve({
        latitude: location.latitude,
        longitude: location.longitude
      });
      
      // 2. 再检查权限状态
      const setting = await uni.getSetting();
      console.log('当前授权状态:', setting.authSetting);
      
      // 3. 如果未授权，弹出授权弹窗
      if (!setting.authSetting['scope.userLocation']) {
        console.log('位置权限未授权，请求授权');
        const confirm = await requestLocationPermission();
        if (!confirm) {
          console.log('用户拒绝授权或授权失败');
          resolve(null);
          return;
        }
      } else {
        console.log('位置权限已授权');
      }
      
    } catch (error: any) {
      console.error('获取定位失败:', error);
      handleLocationError(error);
      resolve(null);
    }
  });
}

// 通过uni.chooseLocation获取地址信息
async function getAddressFromLocation(latitude: number, longitude: number) {
  try {
    uni.request({
      url: 'https://apis.map.qq.com/ws/geocoder/v1/',
      data: {
        location: `${latitude},${longitude}`,
        key: 'MHZBZ-XNLKC-TUT2D-AS7RQ-ODXIF-OBF6I'
      },
      success: (res: any) => {
        const address = res.data.result.address;
        console.log('address',address)
        scopeAddress.value = address || '未知位置'
        fixedPoint.addrName = address || '未知位置'
      }
    });
  } catch (error) {
    console.error('获取地址失败:', error)
    scopeAddress.value = `位置: ${latitude.toFixed(6)}, ${longitude.toFixed(6)}`
    fixedPoint.addrName = '自动获取位置'
  }
}

// 距离计算（简化版）
function isWithinRange(lat1: number, lon1: number, lat2: number, lon2: number, radius: number) {
  // 简化的距离计算，适用于小范围距离判断
  const latDiff = (lat1 - lat2) * 111320  // 纬度每度约111320米
  const lngDiff = (lon1 - lon2) * 111320 * Math.cos(lat1 * Math.PI / 180)
  const distance = Math.sqrt(latDiff * latDiff + lngDiff * lngDiff)
  return distance <= radius
}

// 检查是否在考勤范围内
function checkInScopeStatus() {
  if (!fixedPointList.value.length) return
  
  const inRange = fixedPoints.value.length > 0
  if (inRange) {
    uni.showToast({
      title: '已在考勤范围内',
      icon: 'none'
    })
  }
}

// 重新获取位置
function retryGetLocation() {
  if (retryCount.value >= maxRetryCount) {
    uni.showModal({
      title: '提示',
      content: '定位失败次数过多，请检查设备设置',
      showCancel: false
    })
    return
  }
  updatePosition(true)
}

/* 业务方法 */
function getTAttRecordItemDTOEvent() {
  getTAttRecordItemDTO({ 
    attendanceDate: parseTime(new Date()), 
    employeesCode: userInfo.value.userCode 
  }).then(res => {
    classesData.value = res.data
    fixedPointList.value = classesData.value?.places || []
    earlyMinute.value = res.data?.earlyMinute || ''
    layMinute.value = res.data?.layMinute || ''
  })
}

function getCheckRecordFlag() {
  checkRecordFlag({ 
    employeesCode: userInfo.value.userCode 
  }).then(res => {
    checkData.type = res.data.type
  })
}

async function onCheck() {
  if (isDisabled.value) {
    uni.showToast({
      title: '当前时间不可打卡',
      icon: 'none'
    })
    return
  }
  
  if (isOutside.value) {
    uni.navigateTo({
      url: '/attendance/clockIn/clockInOutside'
    })
    return
  }

  await updatePosition()
  
  if (!inScope.value) {
    uni.showToast({
      title: '请进入考勤范围后进行打卡',
      icon: 'none'
    })
    return
  }

  attCheckEvent()
}

function attCheckEvent() {
  uni.showLoading({ title: '打卡中...', mask: true })
  
  attCheck({
    userName: userInfo.value.nickName,
    employeesCode: userInfo.value.userCode,
    checkTime: parseTime(new Date()),
    longitude: fixedPoint.longitude,
    latitude: fixedPoint.latitude,
    addrName: fixedPoint.addrName,
    actualAddr: scopeAddress.value,
    outSide: isOutside.value ? '1' : '0'
  }).then(res => {
    checkData.time = currentTime.value
    checkData.openState = true
    popupRef.value.open('center')
    getTAttRecordItemDTOEvent()
    getCheckRecordFlag()
    uni.showToast({
      title: res.msg,
      icon: 'none'
    })
  }).finally(() => {
    uni.hideLoading()
  })
}

const popupRef = ref<any>(null)
function onClose() {
  popupRef.value.close()
}
</script>

<template>
  <view class="container full" style="overflow-x: hidden;">
    <UserCard style="width: 100%;"/>
    
    <!-- 定位加载提示 -->
    <!-- <uv-loading v-if="locationLoading" mode="circle" class="loading-overlay" text="定位中..." /> -->
    
    <view class="operateBox">
      <view class="timeList">
        <view class="timeLi" v-for="(item, index) in classesData?.recordItemDurations ?? []" :key="index">
          <view class="timeSlot">
            <view class="timeName">
              <van-icon
                v-if="item.attCheckStatus"
                size="16"
                :color="item.attCheckStatus === '1' ? '#1989fa' : 'rgba(255, 105, 105, 1)'"
                :name="item.clockInTime ? 'checked' : 'warning'" />
              <text>上班{{ item.workingTime }}</text>
            </view>
            <view class="timeState">
              <view class="text">{{ item.clockInTime || '未打卡' }}</view>
              <view class="state" :class="`state${item.attCheckStatus}`" v-if="item.attCheckStatus && item.attCheckStatus !== '1'">
                <DictTag :options="att_status" :value="item.attCheckStatus" />
              </view>
            </view>
          </view>
          <view class="timeSlot">
            <view class="timeName">
              <van-icon
                size="16"
                :color="item.offCheckStatus === '1' ? '#1989fa' : 'rgba(255, 105, 105, 1)'"
                :name="item.clockOutTime ? 'checked' : 'warning'" />
              <text>下班{{ item.closingTime }}</text>
            </view>
            <view class="timeState">
              <view class="text">{{ item.clockOutTime || '未打卡' }}</view>
              <view class="state" :class="`state${item.offCheckStatus}`" v-if="item.offCheckStatus && item.offCheckStatus !== '1'">
                <DictTag :options="att_status" :value="item.offCheckStatus" />
              </view>
            </view>
          </view>
        </view>
      </view>
      
      <view class="clockInBox" :class="{ 'outside': isOutside, 'disabled': isDisabled }">
        <view class="clockInButBox">
          <view class="clockInBut" @click="onCheck">
            <view class="tipe">{{ stateText }}</view>
            <view class="time">{{ currentTime }}</view>
          </view>
        </view>
        <view v-if="!isOutside" class="clockInTipe">{{ scopeStateText }}</view>
        <view v-if="scopeAddress" class="clockInTipeAddress">
          <van-icon name="location" />
          {{ scopeAddress }}
        </view>
        <view v-if="earlyMinute || layMinute" class="clockInBoxTips">
          <text>友好提示：</text>
          <view class="clockInBoxTips-content">
            <template v-if="earlyMinute">上班前{{ earlyMinute }}分钟之内打卡有效</template>
            <template v-if="earlyMinute && layMinute">，</template>
            <view v-if="layMinute">下班后{{ layMinute }}分钟之内打卡有效。</view>
          </view>
        </view>
      </view>
    </view>
    
    <!-- 定位失败重试按钮 -->
    <view v-if="locationError && !locationLoading" class="retry-btn" @click="retryGetLocation">
      <text>重新获取位置</text>
      <van-icon name="replay" size="16" />
    </view>
    
    <uv-popup ref="popupRef" :round="10">
      <view class="checkSuccess">
        <view class="winBg">
          <view class="checkSuccessIcon">
            <image :src="checkSuccessIcon" mode="aspectFit"
            width="120"
            height="120"/>
          </view>
          <view class="checkTime">{{ checkData.time }}</view>
          <view class="tipeText">{{ stateText }}打卡成功</view>
          <div style="margin-top: 50rpx;" >
             <uv-button type="primary" @click="onClose">我知道了</uv-button>
          </div>
         
        </view>
      </view>
    </uv-popup>
  </view>
</template>

<style lang="less" scoped>
.container {
  position: relative;
  display: flex;
  flex-direction: column;
  background: #f9f9f9;
  box-sizing: border-box;
  min-height: 100vh;
  
  .loading-overlay {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    background: rgba(255, 255, 255, 0.8);
    z-index: 9999;
  }
  
  .operateBox {
    position: relative;
    flex: 1;
    margin: 24rpx 0 0;
    padding: 16rpx 16rpx 40rpx 16rpx;
    background-color: rgba(255, 255, 255, 1);
    box-shadow:0 4px 40px  rgba(64, 103, 251, 0.14);;
    border-radius: 20rpx;
    display: flex;
    flex-direction: column;
    .timeList {
      .timeLi {
        margin-bottom: 12rpx;
        width: 100%;
        display: flex;
        justify-content: space-between;
        .timeSlot {
          flex: 1;
          padding: 34rpx 0 22rpx 24rpx;
          width: calc(320rpx - 24rpx);
          background-color: rgba(242, 242, 242, 1);
          border-radius: 14rpx;
          &:last-child {
            margin-left: 20rpx;
          }
          .timeName {
            display: flex;
            align-items: center;
            font-size: 28rpx;
            color: rgba(37, 37, 37, 1);
            .icon{
              margin-right: 8rpx;
            }
          }
          .timeState {
            margin-top: 12rpx;
            display: flex;
            font-size: 24rpx;
            color: #999;
            .text {
              flex: 1;
              overflow: hidden;
            }
            .state{
              margin-left: 8rpx;
              margin-right: 8rpx;
            }
          }
        }
      }
      .timeLi:last-child {
        margin-bottom: 0;
      }
    }
    .clockInBox {
      flex: 1;
      position: relative;
      width: 100%;
      height: auto;
      display: flex;
      justify-content: center;
      flex-direction: column;
      align-items: center;
      /* 外勤 */
      &.outside {
        .clockInButBox {
          background: radial-gradient(50% 26.93%, rgba(7,193,96, 0.2) 0%, rgba(7,193,96, 0.2) 100%);
          .clockInBut {
            background: radial-gradient(63.67% 20.65%, rgba(7,193,96, 1) 0%, rgba(7,193,96, 1) 100%);
            box-shadow: 0 8rpx 34rpx rgba(7,193,96, 1);
          }
        }
      }
      &.disabled {
        .clockInButBox {
          background: radial-gradient(50% 26.93%, #f2f3f5 0%, #f2f3f5 100%);;
          .clockInBut {
                background: radial-gradient(63.67% 20.65%, #c8c9cc 0%, #c8c9cc 100%);
            box-shadow: 0 8rpx 34rpx #c8c9cc;
          }
        }
      }
      .clockInButBox {
        margin-bottom: 48rpx;
        padding: 14rpx;
        width: 260rpx;
        height: 260rpx;
        border-radius: 50%;
        background: radial-gradient(50% 26.93%, rgba(108, 168, 253, 0.2) 0%, rgba(68, 110, 252, 0.2) 100%);
        box-shadow: 0 8rpx 34rpx rgba(107, 166, 253, 0.1);
        box-sizing: content-box;
        .clockInBut {
          width: 260rpx;
          height: 260rpx;
          background: radial-gradient(63.67% 20.65%, rgba(131, 177, 251, 1) 0%, rgba(100, 157, 253, 1) 100%);
          box-shadow: 0 8rpx 34rpx rgba(107, 166, 253, 0.6);
          border-radius: 50%;
          display: flex;
          flex-direction: column;
          align-items: center;
          justify-content: center;
          .tipe {
            font-size: 40rpx;
            font-weight: 500;
            color: #fff;
          }
          .time {
            margin-top: 14rpx;
            font-size: 36rpx;
            color: rgba(255, 255, 255, 0.65);
          }
        }
        .clockInButDisable{
          opacity: 0.5;
        }
      }
      .clockInTipe {
        margin-bottom: 20rpx;
        color: #999999;
        font-size: 28rpx;
      }
      .clockInTipeAddress {
        color: #646566;
      }
      /* 提示信息 */
      .clockInBoxTips {
        display: flex;
        position: absolute;
        bottom: 0;
        left: 0;
        padding: 20rpx 40rpx 0;
        width: 100%;
        color: #969799;
        &-content {
          flex: 1;
          overflow: hidden;
        }
      }
    }
  }
  
  .retry-btn {
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 16rpx 32rpx;
    background-color: #1989fa;
    color: white;
    border-radius: 8rpx;
    font-size: 28rpx;
    margin: 20rpx auto;
    gap: 8rpx;
  }
  
  .checkSuccess{
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background: rgba(0, 0, 0, .4);
    display: flex;
    justify-content: center;
    align-items: center;
    .winBg{
      width: 630rpx;
      height: 766rpx;
      border-radius: 24rpx;
      background: rgba(255, 255, 255, 1);
      display: flex;
      flex-direction: column;
      align-items: center;
      .checkSuccessIcon{
        margin-top: 46rpx;
        width: 372rpx;
        height: 372rpx;
        img{
          width: 100%;
          height: 100%;
        }
      }
      .checkTime{
        margin-top: 24rpx;
        font-size: 50rpx;
        font-weight: 600;
        line-height: 50rpx;
        color: rgba(71, 115, 252, 1);
      }
      .tipeText{
        margin-top: 44rpx;
        font-size: 36rpx;
        font-weight: 500;
        line-height: 36rpx;
        color: rgba(71, 115, 252, 1);
      }
      .but{
        margin-top: 36rpx;
        width: 490rpx;
        height: 84rpx;
        border-radius: 42rpx;
        background: linear-gradient(180deg, rgba(71, 115, 252, 1) 0%, rgba(109, 155, 253, 1) 65.09%, rgba(157, 192, 255, 1) 100%);
        text-align: center;
        line-height: 84rpx;
        font-size: 36rpx;
        color: rgba(255, 255, 255, 1);
      }
    }
  }
}
</style>