<script lang="ts" setup>
import type {
  DingtalkDeptTreeNode,
  StreamEventLog,
  StreamStatus,
  SyncTypeStats,
} from '#/api/core/dingtalk-sync';

import { onBeforeUnmount, onMounted, ref } from 'vue';

import { Link2, RefreshCw } from '@vben/icons';
import { $t } from '@vben/locales';

import {
  ElButton,
  ElCheckbox,
  ElDivider,
  ElForm,
  ElFormItem,
  ElInput,
  ElMessage,
  ElPagination,
  ElScrollbar,
  ElTable,
  ElTableColumn,
  ElTag,
  ElTreeSelect,
} from 'element-plus';

import {
  getDeptTreeApi,
  getStreamEventsApi,
  getStreamStatusApi,
  getSyncConfigApi,
  getSyncStatsApi,
  getSyncStatusApi,
  syncDeptApi,
  syncUserApi,
  testConnectionApi,
  updateSyncConfigApi,
} from '#/api/core/dingtalk-sync';

defineOptions({ name: 'DingtalkSyncForm' });

// ==================== 配置表单 ====================
const configForm = ref({
  corp_id: '',
  app_key: '',
  app_secret: '',
  sync_dept_id: '',
  sync_root_dept_id: '',
  enable_dept_event: '',
  enable_user_event: '',
  callback_url: '',
  callback_token: '',
  callback_aes_key: '',
});

const loading = ref(false);
const saving = ref(false);
const testing = ref(false);
const syncingDept = ref(false);
const syncingUser = ref(false);

// ==================== Stream 模式状态 ====================
const streamStatus = ref<StreamStatus>({
  stream_mode: true,
  running: false,
  total_events: 0,
  last_event_type: null,
  last_event_time: null,
});
const streamLoading = ref(false);

// ==================== 同步统计 ====================
interface StatsRow {
  type: string;
  typeLabel: string;
  total_count: number;
  success_count: number;
  fail_count: number;
  not_synced: number;
  status: null | string;
  sync_time: null | string;
}

const statsData = ref<StatsRow[]>([
  {
    type: 'dept',
    typeLabel: '',
    total_count: 0,
    success_count: 0,
    fail_count: 0,
    not_synced: 0,
    status: null,
    sync_time: null,
  },
  {
    type: 'user',
    typeLabel: '',
    total_count: 0,
    success_count: 0,
    fail_count: 0,
    not_synced: 0,
    status: null,
    sync_time: null,
  },
]);

// ==================== 触发事件 ====================
interface EventRow {
  key: string;
  label: string;
  description: string;
  enabled: boolean;
}

const eventsData = ref<EventRow[]>([
  {
    key: 'enable_dept_event',
    label: '',
    description: '',
    enabled: false,
  },
  {
    key: 'enable_user_event',
    label: '',
    description: '',
    enabled: false,
  },
]);

// ==================== 部门树（同步范围选择） ====================
const deptTreeData = ref<any[]>([]);
const deptTreeLoading = ref(false);
const hasSynced = ref(false);

function transformDeptTree(
  nodes: DingtalkDeptTreeNode[],
): Array<{ children?: any[]; label: string; value: string }> {
  return nodes.map((node) => ({
    value: String(node.dept_id),
    label: node.name,
    children:
      node.children && node.children.length > 0
        ? transformDeptTree(node.children)
        : undefined,
  }));
}

// ==================== 轮询 ====================
let pollTimerDept: null | ReturnType<typeof setInterval> = null;
let pollTimerUser: null | ReturnType<typeof setInterval> = null;

function startPolling(logId: string, type: 'dept' | 'user') {
  const timer = setInterval(async () => {
    try {
      const raw: any = await getSyncStatusApi(logId);
      const res = raw?.data || raw;
      const idx = type === 'dept' ? 0 : 1;
      if (res.status !== 'not_found') {
        statsData.value[idx] = {
          ...statsData.value[idx]!,
          total_count: res.total_count,
          success_count: res.success_count,
          fail_count: res.fail_count,
          not_synced: Math.max(
            0,
            res.total_count - res.success_count - res.fail_count,
          ),
          status: res.status,
          sync_time: res.finished_at,
        };
      }
      if (res.status && res.status !== 'running') {
        stopPolling(type);
        if (type === 'dept') syncingDept.value = false;
        else syncingUser.value = false;
        await loadStats();
      }
    } catch {
      stopPolling(type);
      if (type === 'dept') syncingDept.value = false;
      else syncingUser.value = false;
    }
  }, 2000);

  if (type === 'dept') pollTimerDept = timer;
  else pollTimerUser = timer;
}

function stopPolling(type: 'dept' | 'user') {
  if (type === 'dept' && pollTimerDept) {
    clearInterval(pollTimerDept);
    pollTimerDept = null;
  }
  if (type === 'user' && pollTimerUser) {
    clearInterval(pollTimerUser);
    pollTimerUser = null;
  }
}

// ==================== Stream 增量事件日志 ====================
const streamEvents = ref<StreamEventLog[]>([]);
const streamEventsTotal = ref(0);
const streamEventsPage = ref(1);
const streamEventsPageSize = ref(10);
const streamEventsLoading = ref(false);

async function loadStreamEvents() {
  streamEventsLoading.value = true;
  try {
    const raw: any = await getStreamEventsApi(
      streamEventsPage.value,
      streamEventsPageSize.value,
    );
    const res = raw?.data || raw;
    streamEvents.value = res.items || [];
    streamEventsTotal.value = res.total || 0;
  } catch {
    // ignore
  } finally {
    streamEventsLoading.value = false;
  }
}

function handleEventsPageChange(page: number) {
  streamEventsPage.value = page;
  loadStreamEvents();
}

// ==================== 初始化 ====================
function updateLabels() {
  statsData.value[0]!.typeLabel = $t('dingtalk-sync.syncDept');
  statsData.value[1]!.typeLabel = $t('dingtalk-sync.syncUser');
  eventsData.value[0]!.label = $t('dingtalk-sync.enableSyncDept');
  eventsData.value[0]!.description = $t('dingtalk-sync.enableSyncDeptDesc');
  eventsData.value[1]!.label = $t('dingtalk-sync.enableSyncUser');
  eventsData.value[1]!.description = $t('dingtalk-sync.enableSyncUserDesc');
}

async function loadConfig() {
  loading.value = true;
  try {
    const config = await getSyncConfigApi();
    configForm.value.corp_id = config.corp_id || '';
    configForm.value.app_key = config.app_key || '';
    configForm.value.app_secret = config.app_secret || '';
    configForm.value.sync_dept_id = config.sync_dept_id || '';
    configForm.value.sync_root_dept_id = config.sync_root_dept_id || '';
    configForm.value.enable_dept_event = config.enable_dept_event || '';
    configForm.value.enable_user_event = config.enable_user_event || '';
    configForm.value.callback_url = config.callback_url || '';
    configForm.value.callback_token = config.callback_token || '';
    configForm.value.callback_aes_key = config.callback_aes_key || '';

    eventsData.value[0]!.enabled = config.enable_dept_event === 'true';
    eventsData.value[1]!.enabled = config.enable_user_event === 'true';
  } catch {
    // ignore
  } finally {
    loading.value = false;
  }
}

async function loadStats() {
  try {
    const stats = await getSyncStatsApi();
    const deptStats: SyncTypeStats = stats.dept;
    const userStats: SyncTypeStats = stats.user;

    statsData.value[0] = {
      ...statsData.value[0]!,
      total_count: deptStats.total_count,
      success_count: deptStats.success_count,
      fail_count: deptStats.fail_count,
      not_synced: deptStats.not_synced,
      status: deptStats.status,
      sync_time: deptStats.sync_time,
    };
    statsData.value[1] = {
      ...statsData.value[1]!,
      total_count: userStats.total_count,
      success_count: userStats.success_count,
      fail_count: userStats.fail_count,
      not_synced: userStats.not_synced,
      status: userStats.status,
      sync_time: userStats.sync_time,
    };

    hasSynced.value = deptStats.success_count > 0;
  } catch {
    // ignore
  }
}

// ==================== 连接测试 ====================
async function handleTestConnection() {
  testing.value = true;
  try {
    await testConnectionApi({
      app_key: configForm.value.app_key,
      app_secret: configForm.value.app_secret,
    });
    ElMessage.success($t('dingtalk-sync.testSuccess'));
    await loadDeptTree();
  } catch {
    ElMessage.error($t('dingtalk-sync.testFail'));
  } finally {
    testing.value = false;
  }
}

// ==================== 加载部门树 ====================
async function loadDeptTree() {
  deptTreeLoading.value = true;
  try {
    const tree = await getDeptTreeApi({
      app_key: configForm.value.app_key,
      app_secret: configForm.value.app_secret,
    });
    deptTreeData.value = transformDeptTree(tree);
  } catch {
    // ignore
  } finally {
    deptTreeLoading.value = false;
  }
}

// ==================== 同步操作 ====================
async function handleSyncDept() {
  syncingDept.value = true;
  statsData.value[0]!.status = 'running';
  try {
    const res: any = await syncDeptApi();
    const logId = res?.log_id || res?.data?.log_id;
    if (logId) {
      startPolling(logId, 'dept');
    }
  } catch {
    ElMessage.error($t('dingtalk-sync.syncFail'));
    syncingDept.value = false;
    statsData.value[0]!.status = null;
  }
}

async function handleSyncUser() {
  syncingUser.value = true;
  statsData.value[1]!.status = 'running';
  try {
    const res: any = await syncUserApi();
    const logId = res?.log_id || res?.data?.log_id;
    if (logId) {
      startPolling(logId, 'user');
    }
  } catch {
    ElMessage.error($t('dingtalk-sync.syncFail'));
    syncingUser.value = false;
    statsData.value[1]!.status = null;
  }
}

function handleSync(row: StatsRow) {
  if (row.type === 'dept') {
    handleSyncDept();
  } else {
    handleSyncUser();
  }
}

function isSyncing(row: StatsRow): boolean {
  return row.type === 'dept' ? syncingDept.value : syncingUser.value;
}

// ==================== 状态 Tag ====================
function getStatusType(
  status: null | string,
): 'danger' | 'info' | 'success' | 'warning' {
  switch (status) {
    case 'failed': {
      return 'danger';
    }
    case 'partial': {
      return 'warning';
    }
    case 'running': {
      return 'info';
    }
    case 'success': {
      return 'success';
    }
    default: {
      return 'info';
    }
  }
}

function getStatusLabel(status: null | string): string {
  switch (status) {
    case 'failed': {
      return $t('dingtalk-sync.statusFailed');
    }
    case 'partial': {
      return $t('dingtalk-sync.statusPartial');
    }
    case 'running': {
      return $t('dingtalk-sync.statusRunning');
    }
    case 'success': {
      return $t('dingtalk-sync.statusSuccess');
    }
    default: {
      return '-';
    }
  }
}

// ==================== 事件类型格式化 ====================
function getEventTypeLabel(type: string): string {
  const labels: Record<string, string> = {
    org_dept_create: $t('dingtalk-sync.eventCreate'),
    org_dept_modify: $t('dingtalk-sync.eventModify'),
    org_dept_remove: $t('dingtalk-sync.eventRemove'),
    user_add_org: $t('dingtalk-sync.eventAddUser'),
    user_modify_org: $t('dingtalk-sync.eventModifyUser'),
    user_leave_org: $t('dingtalk-sync.eventLeaveUser'),
    user_active_org: $t('dingtalk-sync.eventActiveUser'),
  };
  return labels[type] || type;
}

function getEventTypeTagType(
  type: string,
): '' | 'danger' | 'success' | 'warning' {
  if (
    type.includes('create') ||
    type.includes('add') ||
    type.includes('active')
  )
    return 'success';
  if (type.includes('modify')) return '';
  if (type.includes('remove') || type.includes('leave')) return 'danger';
  return 'warning';
}

function getTargetTypeLabel(type: string): string {
  if (type === 'dept') return $t('dingtalk-sync.syncDept');
  if (type === 'user') return $t('dingtalk-sync.syncUser');
  return type;
}

// ==================== 保存配置 ====================
async function handleSave() {
  saving.value = true;
  try {
    await updateSyncConfigApi({
      corp_id: configForm.value.corp_id || undefined,
      app_key: configForm.value.app_key || undefined,
      app_secret: configForm.value.app_secret || undefined,
      sync_dept_id: configForm.value.sync_dept_id || undefined,
      sync_root_dept_id: configForm.value.sync_root_dept_id || undefined,
      enable_dept_event: eventsData.value[0]!.enabled ? 'true' : 'false',
      enable_user_event: eventsData.value[1]!.enabled ? 'true' : 'false',
      callback_url: configForm.value.callback_url || undefined,
      callback_token: configForm.value.callback_token || undefined,
      callback_aes_key: configForm.value.callback_aes_key || undefined,
    });
    ElMessage.success($t('dingtalk-sync.saveSuccess'));
  } catch {
    ElMessage.error($t('dingtalk-sync.saveFail'));
  } finally {
    saving.value = false;
  }
}

defineExpose({ save: handleSave, saving });

// ==================== Stream 模式状态 ====================
async function loadStreamStatus() {
  streamLoading.value = true;
  try {
    const raw: any = await getStreamStatusApi();
    const res = raw?.data || raw;
    streamStatus.value = res;
  } catch {
    streamStatus.value.running = false;
  } finally {
    streamLoading.value = false;
  }
}

// ==================== 格式化时间 ====================
function formatTime(val: null | string): string {
  if (!val) return '';
  try {
    return new Date(val).toLocaleString();
  } catch {
    return val;
  }
}

function formatEventType(type: null | string): string {
  if (!type) return $t('dingtalk-sync.streamEventNone');
  const labels: Record<string, string> = {
    user_add_org: `${$t('dingtalk-sync.syncUser')} +`,
    user_modify_org: `${$t('dingtalk-sync.syncUser')} ~`,
    user_leave_org: `${$t('dingtalk-sync.syncUser')} -`,
    user_active_org: `${$t('dingtalk-sync.syncUser')} ✓`,
    org_dept_create: `${$t('dingtalk-sync.syncDept')} +`,
    org_dept_modify: `${$t('dingtalk-sync.syncDept')} ~`,
    org_dept_remove: `${$t('dingtalk-sync.syncDept')} -`,
  };
  return labels[type] || type;
}

onMounted(async () => {
  updateLabels();
  await loadConfig();
  await Promise.all([loadStats(), loadStreamStatus(), loadStreamEvents()]);
});

onBeforeUnmount(() => {
  stopPolling('dept');
  stopPolling('user');
});
</script>

<template>
  <div class="flex h-full flex-col">
    <ElScrollbar class="flex-1">
      <div v-loading="loading" class="space-y-6 p-6">
        <!-- 凭证配置 -->
        <ElForm label-width="120px" label-position="left">
          <ElFormItem :label="$t('dingtalk-sync.corpId')">
            <ElInput
              v-model="configForm.corp_id"
              placeholder="请输入CorpId"
              clearable
              class="!w-[400px]"
            />
          </ElFormItem>
          <ElFormItem :label="$t('dingtalk-sync.appKey')">
            <ElInput
              v-model="configForm.app_key"
              :placeholder="$t('dingtalk-sync.appKeyPlaceholder')"
              clearable
              class="!w-[400px]"
            />
          </ElFormItem>
          <ElFormItem :label="$t('dingtalk-sync.appSecret')">
            <div class="flex items-center gap-3">
              <ElInput
                v-model="configForm.app_secret"
                :placeholder="$t('dingtalk-sync.appSecretPlaceholder')"
                show-password
                clearable
                class="!w-[400px]"
              />
              <ElButton :loading="testing" @click="handleTestConnection">
                <template v-if="!testing" #icon>
                  <Link2 class="size-4" />
                </template>
                {{
                  testing
                    ? $t('dingtalk-sync.testing')
                    : $t('dingtalk-sync.testConnection')
                }}
              </ElButton>
            </div>
          </ElFormItem>

          <!-- 同步范围 -->
          <ElFormItem :label="$t('dingtalk-sync.syncScope')">
            <ElTreeSelect
              v-model="configForm.sync_dept_id"
              :data="deptTreeData"
              :placeholder="$t('dingtalk-sync.syncScopePlaceholder')"
              :loading="deptTreeLoading"
              :disabled="false"
              check-strictly
              filterable
              class="!w-[400px]"
              node-key="value"
              :props="{ label: 'label', children: 'children' }"
            />
          </ElFormItem>
          <div
            class="mb-6 ml-[120px] text-xs"
            style="color: var(--el-text-color-secondary)"
          >
            {{
              hasSynced
                ? $t('dingtalk-sync.syncScopeLocked')
                : $t('dingtalk-sync.syncScopeTip')
            }}
          </div>
        </ElForm>

        <!-- 同步统计表 -->
        <div>
          <ElTable :data="statsData" border stripe>
            <ElTableColumn
              prop="typeLabel"
              :label="$t('dingtalk-sync.syncType')"
              width="100"
            />
            <ElTableColumn
              prop="total_count"
              :label="$t('dingtalk-sync.totalCount')"
              width="80"
              align="center"
            />
            <ElTableColumn
              prop="success_count"
              :label="$t('dingtalk-sync.successCount')"
              width="110"
              align="center"
            />
            <ElTableColumn
              prop="fail_count"
              :label="$t('dingtalk-sync.failCount')"
              width="110"
              align="center"
            />
            <ElTableColumn
              prop="not_synced"
              :label="$t('dingtalk-sync.notSynced')"
              width="100"
              align="center"
            />
            <ElTableColumn
              :label="$t('dingtalk-sync.syncStatus')"
              width="110"
              align="center"
            >
              <template #default="{ row }">
                <ElTag
                  v-if="row.status"
                  :type="getStatusType(row.status)"
                  size="small"
                >
                  {{ getStatusLabel(row.status) }}
                </ElTag>
                <span v-else>-</span>
              </template>
            </ElTableColumn>
            <ElTableColumn
              :label="$t('dingtalk-sync.syncTime')"
              min-width="170"
            >
              <template #default="{ row }">
                {{ formatTime(row.sync_time) }}
              </template>
            </ElTableColumn>
            <ElTableColumn
              :label="$t('dingtalk-sync.operation')"
              width="100"
              align="center"
              fixed="right"
            >
              <template #default="{ row }">
                <ElButton
                  type="primary"
                  link
                  :loading="isSyncing(row)"
                  :disabled="isSyncing(row)"
                  @click="handleSync(row)"
                >
                  <template v-if="!isSyncing(row)" #icon>
                    <RefreshCw class="size-3.5" />
                  </template>
                  {{
                    isSyncing(row)
                      ? $t('dingtalk-sync.syncing')
                      : $t('dingtalk-sync.sync')
                  }}
                </ElButton>
              </template>
            </ElTableColumn>
          </ElTable>
        </div>

        <!-- 触发事件 -->
        <div>
          <div
            class="mb-3 text-sm font-medium"
            style="color: var(--el-text-color-primary)"
          >
            {{ $t('dingtalk-sync.triggerEvents') }}
          </div>
          <ElTable :data="eventsData" border stripe>
            <ElTableColumn width="60" align="center">
              <template #default="{ row }">
                <ElCheckbox v-model="row.enabled" />
              </template>
            </ElTableColumn>
            <ElTableColumn
              prop="label"
              :label="$t('dingtalk-sync.triggerEvent')"
              width="200"
            />
            <ElTableColumn
              prop="description"
              :label="$t('dingtalk-sync.description')"
            />
          </ElTable>
        </div>

        <!-- Stream 模式（实时同步） -->
        <!--        <ElDivider />-->
        <!--        <div>-->
        <!--          <div-->
        <!--            class="mb-2 flex items-center gap-2 text-sm font-medium"-->
        <!--            style="color: var(&#45;&#45;el-text-color-primary)"-->
        <!--          >-->
        <!--            {{ $t('dingtalk-sync.streamConfig') }}-->
        <!--          </div>-->
        <!--          <ElAlert-->
        <!--            type="info"-->
        <!--            :closable="false"-->
        <!--            show-icon-->
        <!--            class="!mb-4"-->
        <!--          >-->
        <!--            <template #default>-->
        <!--              {{ $t('dingtalk-sync.streamConfigTip') }}-->
        <!--            </template>-->
        <!--          </ElAlert>-->

        <!--          <div v-loading="streamLoading">-->
        <!--            <ElDescriptions-->
        <!--              border-->
        <!--              :column="2"-->
        <!--            >-->
        <!--              <ElDescriptionsItem :label="$t('dingtalk-sync.streamTotalEvents')">-->
        <!--                {{ streamStatus.total_events }}-->
        <!--              </ElDescriptionsItem>-->
        <!--              <ElDescriptionsItem :label="$t('dingtalk-sync.streamLastEvent')">-->
        <!--                {{ formatEventType(streamStatus.last_event_type) }}-->
        <!--              </ElDescriptionsItem>-->
        <!--              <ElDescriptionsItem :label="$t('dingtalk-sync.streamLastEventTime')">-->
        <!--                {{ streamStatus.last_event_time ? formatTime(streamStatus.last_event_time) : $t('dingtalk-sync.streamEventNone') }}-->
        <!--              </ElDescriptionsItem>-->
        <!--            </ElDescriptions>-->
        <!--          </div>-->
        <!--        </div>-->

        <!-- Stream 增量事件日志 -->
        <ElDivider />
        <div>
          <div class="mb-3 flex items-center justify-between">
            <span
              class="text-sm font-medium"
              style="color: var(--el-text-color-primary)"
            >
              {{ $t('dingtalk-sync.streamEventLog') }}
            </span>
            <ElButton size="small" @click="loadStreamEvents">
              <template #icon>
                <RefreshCw class="size-3.5" />
              </template>
              {{ $t('dingtalk-sync.refresh') }}
            </ElButton>
          </div>

          <ElTable
            v-loading="streamEventsLoading"
            :data="streamEvents"
            border
            stripe
          >
            <ElTableColumn :label="$t('dingtalk-sync.eventType')" width="140">
              <template #default="{ row }">
                <ElTag :type="getEventTypeTagType(row.event_type)" size="small">
                  {{ getEventTypeLabel(row.event_type) }}
                </ElTag>
              </template>
            </ElTableColumn>
            <ElTableColumn
              :label="$t('dingtalk-sync.targetType')"
              width="90"
              align="center"
            >
              <template #default="{ row }">
                {{ getTargetTypeLabel(row.target_type) }}
              </template>
            </ElTableColumn>
            <ElTableColumn
              prop="target_name"
              :label="$t('dingtalk-sync.targetName')"
              min-width="120"
            >
              <template #default="{ row }">
                {{ row.target_name || '-' }}
              </template>
            </ElTableColumn>
            <ElTableColumn
              :label="$t('dingtalk-sync.eventStatus')"
              width="90"
              align="center"
            >
              <template #default="{ row }">
                <ElTag
                  :type="row.status === 'success' ? 'success' : 'danger'"
                  size="small"
                >
                  {{
                    row.status === 'success'
                      ? $t('dingtalk-sync.statusSuccess')
                      : $t('dingtalk-sync.statusFailed')
                  }}
                </ElTag>
              </template>
            </ElTableColumn>
            <ElTableColumn :label="$t('dingtalk-sync.eventTime')" width="170">
              <template #default="{ row }">
                {{ formatTime(row.event_time) }}
              </template>
            </ElTableColumn>
          </ElTable>

          <div
            v-if="streamEventsTotal > streamEventsPageSize"
            class="mt-3 flex justify-end"
          >
            <ElPagination
              v-model:current-page="streamEventsPage"
              :page-size="streamEventsPageSize"
              :total="streamEventsTotal"
              layout="prev, pager, next"
              small
              @current-change="handleEventsPageChange"
            />
          </div>
        </div>
      </div>
    </ElScrollbar>
  </div>
</template>
