<script setup lang="ts">
import { computed, onActivated, onMounted, ref } from 'vue';
import { userGenderRecord } from '@/constants/business';
import { fetchGetMyProfileDetail, fetchUpdateMyProfile } from '@/service/api';
import { buildFileProxyUrl, uploadFile } from '@/service/api/file';
import { useAuthStore } from '@/store/modules/auth';
import { useAppStore } from '@/store/modules/app';
import { $t } from '@/locales';
import ProfileInfoDialog from './modules/profile-info-dialog.vue';
import ProfilePasswordDialog from './modules/profile-password-dialog.vue';
import { buildProfileUpdatePayload, formatProfileDateTime, resolveProfileRoleLabels } from './modules/profile-model';

defineOptions({ name: 'MyProfile' });

const authStore = useAuthStore();
const appStore = useAppStore();

const loading = ref(false);
const avatarSubmitting = ref(false);
const profile = ref<Api.Auth.MyProfileDetail | null>(null);
const profileInfoVisible = ref(false);
const passwordVisible = ref(false);
const avatarInputRef = ref<HTMLInputElement | null>(null);

const descriptionColumns = computed(() => (appStore.isMobile ? 1 : 2));
const displayName = computed(() => profile.value?.nickname?.trim() || profile.value?.username || '--');
const displayUsername = computed(() => profile.value?.username?.trim() || '--');
const companyText = computed(() => profile.value?.company?.trim() || '--');
const deptText = computed(() => profile.value?.dept?.name?.trim() || profile.value?.deptName?.trim() || '--');
const positionText = computed(
  () => profile.value?.position?.name?.trim() || profile.value?.positionName?.trim() || '--'
);
const mobileText = computed(() => profile.value?.mobile?.trim() || '--');
const emailText = computed(() => profile.value?.email?.trim() || '--');
const genderText = computed(() => {
  const value = profile.value?.sex;

  if (value === null || value === undefined) {
    return '--';
  }

  return $t(userGenderRecord[value]);
});
const roleLabels = computed(() => {
  const roles = profile.value?.roles ?? [];

  if (roles.length === 0) {
    return [];
  }

  return resolveProfileRoleLabels(roles);
});

function getAvatarText() {
  const name = displayName.value;

  return name === '--' ? 'CN' : name.slice(0, 1).toUpperCase();
}

function getEditableProfileValues(current: Api.Auth.MyProfileDetail): Api.Auth.UpdateMyProfileParams {
  return {
    nickname: current.nickname ?? '',
    email: current.email ?? '',
    mobile: current.mobile ?? '',
    sex: current.sex ?? 1,
    avatar: current.avatar ?? ''
  };
}

async function loadProfile() {
  const userId = authStore.userInfo.userId;

  if (!userId) {
    profile.value = null;
    return;
  }

  const { data, error } = await fetchGetMyProfileDetail({
    userId
  });

  if (!error) {
    profile.value = data;
  }
}

async function initPage() {
  loading.value = true;

  await authStore.initUserInfo();
  await loadProfile();

  loading.value = false;
}

function triggerAvatarSelect() {
  if (!profile.value || avatarSubmitting.value) {
    return;
  }

  avatarInputRef.value?.click();
}

async function handleAvatarChange(event: Event) {
  const input = event.target as HTMLInputElement;
  const file = input.files?.[0];
  input.value = '';

  if (!file || !profile.value) {
    return;
  }

  if (!file.type.startsWith('image/')) {
    window.$message?.error('请上传图片文件');
    return;
  }

  avatarSubmitting.value = true;

  const uploadResult = await uploadFile(file, 'avatar');

  if (uploadResult.error) {
    avatarSubmitting.value = false;
    return;
  }

  const avatar = buildFileProxyUrl(uploadResult.data.configId, uploadResult.data.path);
  const payload = buildProfileUpdatePayload({
    ...getEditableProfileValues(profile.value),
    avatar
  });
  const updateResult = await fetchUpdateMyProfile(payload);

  avatarSubmitting.value = false;

  if (updateResult.error) {
    return;
  }

  window.$message?.success('头像更新成功');
  await Promise.all([loadProfile(), authStore.refreshUserInfo()]);
}

async function handleProfileSubmitted() {
  await Promise.all([loadProfile(), authStore.refreshUserInfo()]);
}

onMounted(() => {
  initPage();
});

onActivated(() => {
  initPage();
});
</script>

<template>
  <div v-loading="loading" class="my-profile-page">
    <template v-if="profile">
      <ElCard class="my-profile-hero-card" shadow="never">
        <div class="my-profile-hero">
          <div class="my-profile-hero__identity">
            <button
              class="my-profile-hero__avatar-button"
              type="button"
              :disabled="avatarSubmitting"
              @click="triggerAvatarSelect"
            >
              <ElAvatar v-if="profile.avatar" :src="profile.avatar" :size="88" class="my-profile-hero__avatar" />
              <div v-else class="my-profile-hero__avatar-fallback">{{ getAvatarText() }}</div>
              <div class="my-profile-hero__avatar-mask">
                <span>{{ avatarSubmitting ? '上传中...' : '更换头像' }}</span>
              </div>
            </button>

            <input
              ref="avatarInputRef"
              class="my-profile-hero__avatar-input"
              type="file"
              accept="image/*"
              @change="handleAvatarChange"
            />

            <div class="my-profile-hero__summary">
              <div class="my-profile-hero__title-row">
                <h1 class="my-profile-hero__title">{{ displayName }}</h1>
                <ElTag type="info" effect="plain">个人中心</ElTag>
              </div>
              <p class="my-profile-hero__subtitle">@{{ displayUsername }}</p>
              <div class="my-profile-hero__meta">
                <ElTag effect="plain">{{ companyText }}</ElTag>
                <ElTag effect="plain">{{ deptText }}</ElTag>
                <ElTag effect="plain">{{ positionText }}</ElTag>
              </div>
            </div>
          </div>

          <div class="my-profile-hero__actions">
            <ElButton type="primary" @click="profileInfoVisible = true">编辑基本信息</ElButton>
            <ElButton @click="passwordVisible = true">修改密码</ElButton>
          </div>
        </div>
      </ElCard>

      <div class="my-profile-content">
        <ElCard shadow="never">
          <template #header>
            <div class="my-profile-card__header">
              <span class="my-profile-card__title">基本资料</span>
            </div>
          </template>

          <ElDescriptions :column="descriptionColumns" border>
            <ElDescriptionsItem label="用户名">{{ displayUsername }}</ElDescriptionsItem>
            <ElDescriptionsItem label="昵称">{{ displayName }}</ElDescriptionsItem>
            <ElDescriptionsItem label="手机号">{{ mobileText }}</ElDescriptionsItem>
            <ElDescriptionsItem label="邮箱">{{ emailText }}</ElDescriptionsItem>
            <ElDescriptionsItem label="性别">{{ genderText }}</ElDescriptionsItem>
            <ElDescriptionsItem label="所属公司">{{ companyText }}</ElDescriptionsItem>
            <ElDescriptionsItem label="所属部门">{{ deptText }}</ElDescriptionsItem>
            <ElDescriptionsItem label="所属岗位">{{ positionText }}</ElDescriptionsItem>
            <ElDescriptionsItem label="角色" :span="descriptionColumns">
              <div v-if="roleLabels.length" class="my-profile-role-list">
                <ElTag v-for="roleLabel in roleLabels" :key="roleLabel" type="primary" effect="plain">
                  {{ roleLabel }}
                </ElTag>
              </div>
              <span v-else>--</span>
            </ElDescriptionsItem>
          </ElDescriptions>
        </ElCard>

        <ElCard shadow="never">
          <template #header>
            <div class="my-profile-card__header">
              <span class="my-profile-card__title">登录信息</span>
            </div>
          </template>

          <ElDescriptions :column="descriptionColumns" border>
            <ElDescriptionsItem label="最近登录 IP">{{ profile.loginIp?.trim() || '--' }}</ElDescriptionsItem>
            <ElDescriptionsItem label="最近登录时间">{{ formatProfileDateTime(profile.loginDate) }}</ElDescriptionsItem>
            <ElDescriptionsItem label="账号创建时间" :span="descriptionColumns">
              {{ formatProfileDateTime(profile.createTime) }}
            </ElDescriptionsItem>
          </ElDescriptions>
        </ElCard>
      </div>
    </template>

    <ElEmpty v-else description="未获取到个人信息" />

    <ProfileInfoDialog v-model:visible="profileInfoVisible" :profile="profile" @submitted="handleProfileSubmitted" />
    <ProfilePasswordDialog v-model:visible="passwordVisible" :username="profile?.username" />
  </div>
</template>

<style scoped>
.my-profile-page {
  display: flex;
  flex-direction: column;
  gap: 16px;
}

.my-profile-hero-card {
  overflow: hidden;
  border: 1px solid rgb(226 232 240 / 92%);
  background:
    radial-gradient(circle at top left, rgb(14 116 144 / 12%), transparent 32%),
    radial-gradient(circle at bottom right, rgb(16 185 129 / 10%), transparent 26%),
    linear-gradient(135deg, rgb(255 255 255 / 99%), rgb(248 250 252 / 98%));
}

.my-profile-hero {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 16px;
  align-items: center;
}

.my-profile-hero__identity {
  display: flex;
  min-width: 0;
  align-items: center;
  gap: 18px;
}

.my-profile-hero__avatar-button {
  position: relative;
  display: inline-flex;
  width: 88px;
  height: 88px;
  align-items: center;
  justify-content: center;
  border: none;
  border-radius: 999px;
  padding: 0;
  overflow: hidden;
  background: transparent;
  cursor: pointer;
}

.my-profile-hero__avatar-button:disabled {
  cursor: not-allowed;
}

.my-profile-hero__avatar,
.my-profile-hero__avatar-fallback {
  width: 88px;
  height: 88px;
}

.my-profile-hero__avatar-fallback {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 999px;
  background: linear-gradient(135deg, rgb(14 116 144 / 92%), rgb(15 118 110 / 84%));
  color: #fff;
  font-size: 28px;
  font-weight: 700;
}

.my-profile-hero__avatar-mask {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background-color: rgb(15 23 42 / 52%);
  color: #fff;
  font-size: 12px;
  font-weight: 600;
  opacity: 0;
  transition: opacity 0.2s ease;
}

.my-profile-hero__avatar-button:hover .my-profile-hero__avatar-mask,
.my-profile-hero__avatar-button:focus-visible .my-profile-hero__avatar-mask {
  opacity: 1;
}

.my-profile-hero__avatar-input {
  display: none;
}

.my-profile-hero__summary {
  display: flex;
  min-width: 0;
  flex-direction: column;
  gap: 10px;
}

.my-profile-hero__title-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
}

.my-profile-hero__title {
  margin: 0;
  color: rgb(15 23 42 / 98%);
  font-size: 28px;
  line-height: 1.15;
  letter-spacing: -0.02em;
}

.my-profile-hero__subtitle {
  margin: 0;
  color: rgb(100 116 139 / 92%);
  font-size: 14px;
}

.my-profile-hero__meta {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.my-profile-hero__actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: 10px;
}

.my-profile-content {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 16px;
}

.my-profile-card__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.my-profile-card__title {
  color: rgb(15 23 42 / 98%);
  font-size: 15px;
  font-weight: 700;
}

.my-profile-role-list {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

@media (width <= 960px) {
  .my-profile-hero {
    grid-template-columns: 1fr;
  }

  .my-profile-hero__actions {
    justify-content: flex-start;
  }

  .my-profile-content {
    grid-template-columns: 1fr;
  }
}

@media (width <= 640px) {
  .my-profile-hero__identity {
    flex-direction: column;
    align-items: flex-start;
  }

  .my-profile-hero__title {
    font-size: 24px;
  }
}
</style>
