<script setup>
import { computed, onBeforeUnmount, ref } from 'vue'
import { ElMessage } from 'element-plus'
import QrcodeVue from 'qrcode.vue'

import { socialLoginUrl, socialPoll } from '../api/auth'

const props = defineProps({
  providers: {
    type: Array,
    default: () => [],
  },
  mode: {
    type: String,
    default: 'login',
  },
  redirectUri: {
    type: String,
    required: true,
  },
  block: {
    type: Boolean,
    default: false,
  },
})

const emit = defineEmits(['error'])

const providerLabels = {
  qq: 'QQ',
  wx: '微信',
  alipay: '支付宝',
}

const loadingProvider = ref('')
const qrOpen = ref(false)
const qrValue = ref('')
const qrProvider = ref('wx')
let pollTimer = null
let pollStartedAt = 0

const enabledProviders = computed(() => props.providers.filter((item) => providerLabels[item]))

function stopPolling() {
  if (pollTimer) {
    window.clearTimeout(pollTimer)
    pollTimer = null
  }
}

function closeQr() {
  stopPolling()
  qrOpen.value = false
  qrValue.value = ''
}

function qrPrompt(provider) {
  if (provider === 'wx') return '请使用微信扫描二维码点关注后登录'
  if (provider === 'qq') return '请使用 QQ 扫描二维码登录'
  return '请使用支付宝扫描二维码登录'
}

function providerIcon(provider) {
  if (provider === 'wx') return '微'
  if (provider === 'qq') return 'Q'
  return '支'
}

function emitError(error, fallback) {
  const data = error?.response?.data
  const message = data?.error || data?.message || fallback
  emit('error', message)
  ElMessage.error(message)
}

function schedulePoll(provider, state, intervalSeconds) {
  stopPolling()
  pollStartedAt = Date.now()
  const tick = async () => {
    if (Date.now() - pollStartedAt > 5 * 60 * 1000) {
      closeQr()
      ElMessage.warning('二维码已过期，请重新获取')
      return
    }
    try {
      const result = await socialPoll({ provider, state })
      if (result?.status === 'authorized' && result?.url) {
        closeQr()
        window.location.assign(result.url)
        return
      }
      pollTimer = window.setTimeout(tick, Math.max(Number(intervalSeconds || 2), 2) * 1000)
    } catch (error) {
      closeQr()
      emitError(error, '扫码状态获取失败，请重新尝试')
    }
  }
  pollTimer = window.setTimeout(tick, Math.max(Number(intervalSeconds || 2), 2) * 1000)
}

async function start(provider) {
  if (loadingProvider.value) return
  loadingProvider.value = provider
  try {
    const data = await socialLoginUrl({
      provider,
      mode: props.mode === 'bind' ? 'bind' : 'login',
      redirect_uri: props.redirectUri,
    })
    if (provider !== 'wx') {
      window.location.assign(data.url)
      return
    }
    const value = data.scan_url || data.qrcode || data.url
    if (!value || !data.scan_state) {
      ElMessage.error('微信二维码获取失败')
      return
    }
    qrProvider.value = provider
    qrValue.value = value
    qrOpen.value = true
    schedulePoll(provider, data.scan_state, data.scan_poll_interval || 2)
  } catch (error) {
    emitError(error, '获取聚合登录地址失败')
  } finally {
    loadingProvider.value = ''
  }
}

onBeforeUnmount(() => {
  stopPolling()
})
</script>

<template>
  <div v-if="enabledProviders.length" class="social-login-buttons" :class="{ block }">
    <button
      v-for="provider in enabledProviders"
      :key="provider"
      type="button"
      class="social-btn"
      :class="`provider-${provider}`"
      :disabled="Boolean(loadingProvider)"
      @click="start(provider)"
    >
      <span class="social-icon">{{ providerIcon(provider) }}</span>
      <span>{{ mode === 'bind' ? `绑定${providerLabels[provider]}` : `${providerLabels[provider]}登录` }}</span>
    </button>

    <el-dialog v-model="qrOpen" :title="`${providerLabels[qrProvider]}登录`" width="min(340px, 92vw)" @close="closeQr">
      <div class="social-qr-box">
        <QrcodeVue v-if="qrValue" :value="qrValue" :size="220" level="M" />
        <div class="social-qr-prompt">{{ qrPrompt(qrProvider) }}</div>
      </div>
    </el-dialog>
  </div>
</template>

<style scoped>
.social-login-buttons {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  flex-wrap: wrap;
}

.social-login-buttons.block {
  align-items: stretch;
  flex-direction: column;
}

.social-btn {
  height: 40px;
  border-radius: 10px;
  border: 1px solid rgba(17, 24, 39, 0.14);
  background: #fff;
  color: #111827;
  font-size: 13px;
  font-weight: 800;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 0 12px;
}

.block .social-btn {
  width: 100%;
}

.social-btn:disabled {
  cursor: not-allowed;
  opacity: 0.7;
}

.social-btn:hover:not(:disabled) {
  background: #f8fafc;
}

.social-icon {
  width: 22px;
  height: 22px;
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: #fff;
  font-size: 12px;
  line-height: 1;
}

.provider-wx .social-icon {
  background: #16a34a;
}

.provider-qq .social-icon {
  background: #2563eb;
}

.provider-alipay .social-icon {
  background: #1677ff;
}

.social-qr-box {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
}

.social-qr-prompt {
  font-size: 13px;
  color: #374151;
  text-align: center;
}
</style>
