/**
 * 一次性探针：拉租户全部 active 用户，按 mailNickname 前缀 + displayName 关键词
 * 聚类，敲定"自动入组"功能的命名黑名单。
 *
 * 跑法：
 *   cd backend
 *   TS_NODE_COMPILER_OPTIONS='{"module":"commonjs","moduleResolution":"node","resolvePackageJsonExports":false}' \
 *     npx ts-node --transpile-only scripts/probes/graph-naming-probe.ts
 *
 * 输出：
 *   - 总用户数 / Member / Guest 分布
 *   - mailNickname 下划线/连字符切分后的前缀 top 30
 *   - displayName 含关键词（room/conf/resource/meeting/shared/team/list/distro/test）的命中
 *   - accountEnabled=false 的命名样本
 */

import 'dotenv/config';
import { ClientSecretCredential } from '@azure/identity';
import { Client } from '@microsoft/microsoft-graph-client';
import { TokenCredentialAuthenticationProvider } from '@microsoft/microsoft-graph-client/authProviders/azureTokenCredentials';

interface RawUser {
  id: string;
  displayName?: string;
  mail?: string;
  mailNickname?: string;
  userPrincipalName?: string;
  userType?: string;
  accountEnabled?: boolean;
}

async function main() {
  const tenantId = process.env.AZURE_TENANT_ID!;
  const clientId = process.env.AZURE_CLIENT_ID!;
  const clientSecret = process.env.AZURE_CLIENT_SECRET!;
  if (!tenantId || !clientId || !clientSecret) {
    console.error('缺少 AZURE_TENANT_ID / AZURE_CLIENT_ID / AZURE_CLIENT_SECRET');
    process.exit(1);
  }

  const cred = new ClientSecretCredential(tenantId, clientId, clientSecret);
  const client = Client.initWithMiddleware({
    authProvider: new TokenCredentialAuthenticationProvider(cred, {
      scopes: ['https://graph.microsoft.com/.default'],
    }),
  });

  console.log(`📥 拉取租户 ${tenantId.slice(0, 8)}... 全量 user（无 enabled 过滤，看完整命名分布）`);

  const all: RawUser[] = [];
  let resp: any = await client
    .api('/users')
    .select('id,displayName,mail,mailNickname,userPrincipalName,userType,accountEnabled')
    .top(999)
    .get();
  all.push(...resp.value);
  while (resp['@odata.nextLink']) {
    process.stdout.write(`\r  拉到 ${all.length}...`);
    resp = await client.api(resp['@odata.nextLink']).get();
    all.push(...resp.value);
  }
  console.log(`\n✅ 共 ${all.length} 条`);

  const member = all.filter((u) => u.userType === 'Member');
  const guest = all.filter((u) => u.userType === 'Guest');
  const enabled = all.filter((u) => u.accountEnabled);
  const disabled = all.filter((u) => !u.accountEnabled);

  console.log('\n## 总览');
  console.log(`  Member: ${member.length} | Guest: ${guest.length} | Other: ${all.length - member.length - guest.length}`);
  console.log(`  enabled: ${enabled.length} | disabled: ${disabled.length}`);

  const nonGuestEnabled = all.filter((u) => u.accountEnabled && u.userType === 'Member');

  // ===== mailNickname 前缀分布 =====
  const prefixCount = new Map<string, number>();
  const prefixSamples = new Map<string, string[]>();
  for (const u of nonGuestEnabled) {
    const nick = u.mailNickname || '';
    if (!nick) continue;
    // 切分：_ - . 都算分隔符
    const m = nick.match(/^([A-Za-z]+)[_\-.]/);
    const prefix = m ? m[1].toLowerCase() : '__no_separator__';
    prefixCount.set(prefix, (prefixCount.get(prefix) || 0) + 1);
    const samples = prefixSamples.get(prefix) || [];
    if (samples.length < 5) {
      samples.push(`${nick}  (${u.displayName})`);
      prefixSamples.set(prefix, samples);
    }
  }

  console.log('\n## mailNickname 前缀（active Member）top 40');
  console.log('  样本量越大越值得作为黑/白名单候选');
  const sortedPrefixes = Array.from(prefixCount.entries())
    .sort((a, b) => b[1] - a[1])
    .slice(0, 40);
  for (const [prefix, count] of sortedPrefixes) {
    const samples = prefixSamples.get(prefix) || [];
    console.log(`  ${count.toString().padStart(4)}  ${prefix.padEnd(20)} | ${samples.slice(0, 3).join(' | ')}`);
  }

  // ===== displayName 关键词命中 =====
  const keywords = [
    'room', 'conf', 'meeting', 'resource', 'equipment', 'projector', 'phone',
    'shared', 'team', 'distro', 'list', 'group', 'mailbox',
    '会议室', '资源', '共享', '组', '部门',
    'leaver', 'terminated', 'disabled', 'deprecated',
    'test', 'temp', 'demo', 'admin', 'service', 'svc',
  ];
  console.log('\n## displayName / mailNickname 含关键词的命中（active Member）');
  for (const kw of keywords) {
    const hits = nonGuestEnabled.filter(
      (u) =>
        u.displayName?.toLowerCase().includes(kw.toLowerCase()) ||
        u.mailNickname?.toLowerCase().includes(kw.toLowerCase()),
    );
    if (hits.length > 0) {
      console.log(`  [${kw}] ${hits.length} 条`);
      for (const u of hits.slice(0, 3)) {
        console.log(`    - ${u.mailNickname?.padEnd(30) || '(no nickname)'} | ${u.displayName} | ${u.mail || '(no mail)'}`);
      }
    }
  }

  // ===== disabled 用户命名样本 =====
  console.log('\n## disabled 用户命名样本（前 10）');
  for (const u of disabled.slice(0, 10)) {
    console.log(`  - ${u.mailNickname?.padEnd(30) || '(no nickname)'} | ${u.displayName} | userType=${u.userType}`);
  }

  // ===== 没 mail 的 Member 样本 =====
  const noMail = nonGuestEnabled.filter((u) => !u.mail);
  console.log(`\n## 没有 mail 的 active Member（${noMail.length} 条，前 10）`);
  for (const u of noMail.slice(0, 10)) {
    console.log(`  - ${u.mailNickname?.padEnd(30) || '(no nickname)'} | ${u.displayName} | UPN=${u.userPrincipalName}`);
  }

  console.log('\n✅ 探针完成。基于上面分布，敲定黑名单前缀 + 关键词后写入 outlook-sync-account-filter.ts');
}

main().catch((err) => {
  console.error('❌ 探针失败:', err.message);
  if (err.statusCode === 403) {
    console.error('   → 权限不足，检查 User.Read.All admin consent 是否生效');
  }
  process.exit(1);
});
