<script setup lang="ts">
import { computed, ref, watch } from 'vue';
import { useMediaQuery } from '@vueuse/core';
import { LAYOUT_SCROLL_EL_ID } from '@sa/materials';
import { objectContextDomainConfigs } from '@/constants/object-context';
import {
  fetchChangeProductStatus,
  fetchCreateProductMember,
  fetchDeleteProduct,
  fetchGetProductMembers,
  fetchGetProductSettings,
  fetchGetRoleSimpleList,
  fetchGetUserSimpleList,
  fetchInactiveProductMember,
  fetchUpdateProductMember,
  fetchUpdateProductSettingBaseInfo
} from '@/service/api';
import { useAuthStore } from '@/store/modules/auth';
import { useObjectContextStore } from '@/store/modules/object-context';
import { useThemeStore } from '@/store/modules/theme';
import { useRouterPush } from '@/hooks/common/router';
import { useCurrentProduct } from '../shared/use-current-product';
import BaseInfoDialog from './modules/base-info-dialog.vue';
import MemberOperateDialog from './modules/member-operate-dialog.vue';
import MemberRemoveDialog from './modules/member-remove-dialog.vue';
import ProductDeleteDialog from './modules/product-delete-dialog.vue';
import SettingAnchorNav from './modules/setting-anchor-nav.vue';
import SettingBaseInfoCard from './modules/setting-base-info-card.vue';
import SettingDangerZone from './modules/setting-danger-zone.vue';
import SettingLifecyclePanel from './modules/setting-lifecycle-panel.vue';
import SettingTeamPanel from './modules/setting-team-panel.vue';
import StatusActionDialog from './modules/status-action-dialog.vue';
import {
  type ProductSettingSectionKey,
  canManageProductTeam,
  getProductSettingSectionKeys,
  resolveVisibleProductSettingSectionKey,
  resolveVisibleProductSettingSections
} from './shared';

defineOptions({ name: 'ProductSetting' });

const authStore = useAuthStore();
const objectContextStore = useObjectContextStore();
const themeStore = useThemeStore();
const { routerPush } = useRouterPush();
const { currentObjectId, currentProduct } = useCurrentProduct();
const isCompactLayout = useMediaQuery('(max-width: 1280px)');

const productDomainConfig = objectContextDomainConfigs.find(config => config.domainKey === 'product') || null;

const allAnchorItems = [
  { key: 'base-info', label: '基础信息' },
  { key: 'team', label: '团队管理' },
  { key: 'lifecycle', label: '生命周期管理' },
  { key: 'danger', label: '危险操作' }
] as const;

const anchorLabelMap = new Map(allAnchorItems.map(item => [item.key, item.label]));

const sectionIdMap: Record<ProductSettingSectionKey, string> = {
  'base-info': 'product-setting-base-info',
  team: 'product-setting-team',
  lifecycle: 'product-setting-lifecycle',
  danger: 'product-setting-danger'
};

const activeAnchorKey = ref<ProductSettingSectionKey>('base-info');
const pageLoading = ref(false);
const memberLoading = ref(false);
const baseInfoVisible = ref(false);
const memberOperateVisible = ref(false);
const memberRemoveVisible = ref(false);
const statusActionVisible = ref(false);
const deleteVisible = ref(false);
const memberOperateMode = ref<'create' | 'edit'>('create');
const selectedMember = ref<Api.Product.ProductMember | null>(null);
const selectedAction = ref<Api.Product.ProductLifecycleAction | null>(null);

const settings = ref<Api.Product.ProductSettings | null>(null);
const members = ref<Api.Product.ProductMember[]>([]);
const roleOptions = ref<Api.SystemManage.RoleSimple[]>([]);
const userOptions = ref<Api.SystemManage.UserSimple[]>([]);

const currentManager = computed(() => members.value.find(item => item.managerFlag && item.status === 0) || null);
const baseInfo = computed(() => settings.value?.baseInfo || null);
const lifecycle = computed(() => settings.value?.lifecycle || null);
const canManageTeam = computed(() =>
  canManageProductTeam({
    buttonCodes: objectContextStore.buttonCodes,
    loginUserId: authStore.userInfo.userId,
    currentManagerUserId: currentManager.value?.userId
  })
);
const visibleSectionKeys = computed(() =>
  resolveVisibleProductSettingSections(getProductSettingSectionKeys(), objectContextStore.buttonCodes)
);
const anchorItems = computed(() =>
  visibleSectionKeys.value.map(key => ({
    key,
    label: anchorLabelMap.get(key) || key
  }))
);
const layoutScrollTarget = `#${LAYOUT_SCROLL_EL_ID}`;
const anchorAffixOffset = computed(() => {
  const fixedTopInset = themeStore.fixedHeaderAndTab
    ? themeStore.header.height + (themeStore.tabVisible ? themeStore.tab.height : 0)
    : 0;

  return fixedTopInset + 16;
});
const anchorShellInlineStyle = computed(() => ({
  maxHeight: isCompactLayout.value ? '' : `calc(100vh - ${anchorAffixOffset.value + 16}px)`
}));
const showLifecycleSection = computed(() => visibleSectionKeys.value.includes('lifecycle'));
const showDangerSection = computed(() => visibleSectionKeys.value.includes('danger'));

async function loadSettings() {
  if (!currentObjectId.value) {
    settings.value = null;
    return;
  }

  const { error, data } = await fetchGetProductSettings(currentObjectId.value);

  if (error || !data) {
    settings.value = null;
    return;
  }

  settings.value = data;
}

async function loadMembers() {
  if (!currentObjectId.value) {
    members.value = [];
    return;
  }

  memberLoading.value = true;

  const { error, data } = await fetchGetProductMembers(currentObjectId.value);

  memberLoading.value = false;

  if (error || !data) {
    members.value = [];
    return;
  }

  members.value = data;
}

async function loadRoleOptions() {
  const { error, data } = await fetchGetRoleSimpleList({
    scopeType: 'object',
    objectType: 'product'
  });

  if (error || !data) {
    roleOptions.value = [];
    return;
  }

  roleOptions.value = data;
}

async function loadUserOptions() {
  const { error, data } = await fetchGetUserSimpleList();

  if (error || !data) {
    userOptions.value = [];
    return;
  }

  userOptions.value = data;
}

async function refreshContextSummary() {
  if (!productDomainConfig || !currentObjectId.value) {
    return;
  }

  await objectContextStore.enterContext(productDomainConfig, currentObjectId.value);
}

async function loadPageData() {
  if (!currentObjectId.value) {
    return;
  }

  pageLoading.value = true;

  await Promise.all([loadSettings(), loadMembers(), loadRoleOptions(), loadUserOptions()]);

  pageLoading.value = false;
}

function scrollToSection(key: string) {
  if (!(key in sectionIdMap)) {
    return;
  }

  const resolvedKey = key as ProductSettingSectionKey;

  if (!visibleSectionKeys.value.includes(resolvedKey)) {
    return;
  }

  activeAnchorKey.value = resolvedKey;
  const target = document.getElementById(sectionIdMap[resolvedKey]);

  target?.scrollIntoView({
    behavior: 'smooth',
    block: 'start'
  });
}

function openCreateMember() {
  memberOperateMode.value = 'create';
  selectedMember.value = null;
  memberOperateVisible.value = true;
}

function openEditMember(member: Api.Product.ProductMember) {
  memberOperateMode.value = 'edit';
  selectedMember.value = member;
  memberOperateVisible.value = true;
}

function openRemoveMember(member: Api.Product.ProductMember) {
  selectedMember.value = member;
  memberRemoveVisible.value = true;
}

function openLifecycleAction(action: Api.Product.ProductLifecycleAction) {
  selectedAction.value = action;
  statusActionVisible.value = true;
}

async function handleSubmitBaseInfo(payload: Api.Product.UpdateProductSettingBaseInfoParams) {
  if (!currentObjectId.value) {
    return;
  }

  const result = await fetchUpdateProductSettingBaseInfo(currentObjectId.value, payload);

  if (result.error) {
    return;
  }

  window.$message?.success('基础信息更新成功');
  baseInfoVisible.value = false;

  await Promise.all([loadSettings(), refreshContextSummary()]);
}

async function handleSubmitMemberOperate(event: {
  mode: 'create' | 'edit';
  memberId?: string;
  managerChanged: boolean;
  payload: Api.Product.CreateProductMemberParams | Api.Product.UpdateProductMemberParams;
}) {
  if (!currentObjectId.value) {
    return;
  }

  const result =
    event.mode === 'create'
      ? await fetchCreateProductMember(currentObjectId.value, event.payload as Api.Product.CreateProductMemberParams)
      : await fetchUpdateProductMember(
          currentObjectId.value,
          event.memberId || '',
          event.payload as Api.Product.UpdateProductMemberParams
        );

  if (result.error) {
    return;
  }

  window.$message?.success(event.mode === 'create' ? '成员新增成功' : '成员角色调整成功');
  memberOperateVisible.value = false;

  await Promise.all([loadMembers(), loadSettings()]);

  if (event.managerChanged) {
    await refreshContextSummary();
  }
}

async function handleSubmitRemoveMember(payload: Api.Product.InactiveProductMemberParams) {
  if (!currentObjectId.value || !selectedMember.value?.id) {
    return;
  }

  const result = await fetchInactiveProductMember(currentObjectId.value, selectedMember.value.id, payload);

  if (result.error) {
    return;
  }

  window.$message?.success('成员移出成功');
  memberRemoveVisible.value = false;

  await Promise.all([loadMembers(), loadSettings()]);
}

async function handleSubmitLifecycleAction(payload: Api.Product.ChangeProductStatusParams) {
  if (!currentObjectId.value || !selectedAction.value) {
    return;
  }

  const result = await fetchChangeProductStatus({
    ...payload,
    id: currentObjectId.value
  });

  if (result.error) {
    return;
  }

  window.$message?.success(`${selectedAction.value.actionName}成功`);
  statusActionVisible.value = false;

  await Promise.all([loadSettings(), refreshContextSummary()]);
}

async function handleSubmitDelete(payload: Api.Product.DeleteProductParams) {
  const result = await fetchDeleteProduct(payload);

  if (result.error) {
    return;
  }

  window.$message?.success('产品删除成功');
  deleteVisible.value = false;
  objectContextStore.clearContext();

  await routerPush({
    path: '/product/list'
  });
}

watch(
  visibleSectionKeys,
  sectionKeys => {
    activeAnchorKey.value = resolveVisibleProductSettingSectionKey(activeAnchorKey.value, sectionKeys);
  },
  {
    immediate: true
  }
);

watch(
  () => currentObjectId.value,
  async objectId => {
    if (!objectId) {
      settings.value = null;
      members.value = [];
      return;
    }

    await loadPageData();
  },
  { immediate: true }
);
</script>

<template>
  <div v-loading="pageLoading" class="product-setting-page">
    <div class="product-setting-page__body">
      <div class="product-setting-page__aside">
        <div v-if="isCompactLayout" class="product-setting-page__aside-shell" :style="anchorShellInlineStyle">
          <SettingAnchorNav :items="anchorItems" :active-key="activeAnchorKey" @select="scrollToSection" />
        </div>
        <ElAffix
          v-else
          class="product-setting-page__aside-affix"
          :offset="anchorAffixOffset"
          :target="layoutScrollTarget"
          teleported
        >
          <div class="product-setting-page__aside-shell" :style="anchorShellInlineStyle">
            <SettingAnchorNav :items="anchorItems" :active-key="activeAnchorKey" @select="scrollToSection" />
          </div>
        </ElAffix>
      </div>

      <div class="product-setting-page__content">
        <section :id="sectionIdMap['base-info']" class="product-setting-page__section">
          <SettingBaseInfoCard :base-info="baseInfo" @edit="baseInfoVisible = true" />
        </section>

        <section :id="sectionIdMap.team" class="product-setting-page__section">
          <SettingTeamPanel
            :members="members"
            :role-options="roleOptions"
            :loading="memberLoading"
            :readonly="!canManageTeam"
            @create="openCreateMember"
            @edit="openEditMember"
            @remove="openRemoveMember"
          />
        </section>

        <section v-if="showLifecycleSection" :id="sectionIdMap.lifecycle" class="product-setting-page__section">
          <SettingLifecyclePanel :lifecycle="lifecycle" @action="openLifecycleAction" />
        </section>

        <section v-if="showDangerSection" :id="sectionIdMap.danger" class="product-setting-page__section">
          <SettingDangerZone
            :product-name="baseInfo?.name || currentProduct?.name || ''"
            @delete="deleteVisible = true"
          />
        </section>
      </div>
    </div>

    <BaseInfoDialog v-model:visible="baseInfoVisible" :base-info="baseInfo" @submit="handleSubmitBaseInfo" />
    <MemberOperateDialog
      v-model:visible="memberOperateVisible"
      :mode="memberOperateMode"
      :member="selectedMember"
      :current-manager="currentManager"
      :role-options="roleOptions"
      :user-options="userOptions"
      :disabled-user-ids="members.filter(member => member.status === 0).map(member => member.userId)"
      @submit="handleSubmitMemberOperate"
    />
    <MemberRemoveDialog
      v-model:visible="memberRemoveVisible"
      :member="selectedMember"
      @submit="handleSubmitRemoveMember"
    />
    <StatusActionDialog
      v-model:visible="statusActionVisible"
      :action="selectedAction"
      @submit="handleSubmitLifecycleAction"
    />
    <ProductDeleteDialog
      v-model:visible="deleteVisible"
      :product-id="currentObjectId"
      :product-name="baseInfo?.name || currentProduct?.name || ''"
      @submit="handleSubmitDelete"
    />
  </div>
</template>

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

.product-setting-page__body {
  display: grid;
  grid-template-columns: 220px minmax(0, 1fr);
  gap: 16px;
  align-items: stretch;
}

.product-setting-page__aside {
  min-width: 0;
  align-self: stretch;
}

.product-setting-page__aside-affix {
  display: block;
  width: 100%;
}

.product-setting-page__aside-shell {
  min-height: 100%;
  padding: 18px 16px;
  border: 1px solid rgb(226 232 240 / 92%);
  border-radius: 20px;
  background:
    radial-gradient(circle at top left, rgb(15 118 110 / 7%), transparent 34%),
    linear-gradient(180deg, rgb(255 255 255 / 99%), rgb(248 250 252 / 97%));
  box-sizing: border-box;
  overflow-y: auto;
  scrollbar-gutter: stable;
}

.product-setting-page__content {
  display: flex;
  flex-direction: column;
  gap: 16px;
}

.product-setting-page__section {
  scroll-margin-top: 16px;
}

@media (width <= 1280px) {
  .product-setting-page__body {
    grid-template-columns: 1fr;
  }

  .product-setting-page__aside-shell {
    min-height: auto;
    overflow: visible;
  }
}
</style>
