/**
 * InternalAppSlugService Unit Tests
 *
 * 覆盖 06-data-model.md §2.1 + 01-prd.md §核心业务约束 的纯字符串变换逻辑：
 * - normalizeEmployeeSlug: mailNickname → 候选 slug（含 20 字符截断 + SHA1 后缀）
 * - validateAppSlug: 字符集 / 长度 / 保留字白名单
 *
 * 纯逻辑无 DB 依赖，符合 CLAUDE.md §测试"复杂纯计算逻辑可写单元测试"例外。
 */

import { InternalAppSlugService } from '@/modules/internal-app-platform/services/slug.service';

describe('InternalAppSlugService', () => {
  let svc: InternalAppSlugService;

  beforeEach(() => {
    svc = new InternalAppSlugService();
  });

  describe('normalizeEmployeeSlug', () => {
    it('简单英文名直接小写化', () => {
      expect(svc.normalizeEmployeeSlug('zhangsan')).toBe('zhangsan');
      expect(svc.normalizeEmployeeSlug('ZhangSan')).toBe('zhangsan');
    });

    it('空格 / 标点替换为单个连字符', () => {
      expect(svc.normalizeEmployeeSlug('Zhang San')).toBe('zhang-san');
      expect(svc.normalizeEmployeeSlug('Zhang.San@FF')).toBe('zhang-san-ff');
    });

    it('连续非法字符合并为单个 -', () => {
      expect(svc.normalizeEmployeeSlug('zhang___san')).toBe('zhang-san');
      expect(svc.normalizeEmployeeSlug('zhang...san')).toBe('zhang-san');
    });

    it('首尾 - 被去除', () => {
      expect(svc.normalizeEmployeeSlug('-zhang-')).toBe('zhang');
      expect(svc.normalizeEmployeeSlug('.zhang.')).toBe('zhang');
    });

    it('≤20 字符不截断', () => {
      const slug = svc.normalizeEmployeeSlug('abcdefghij1234567890'); // 20 字符
      expect(slug).toBe('abcdefghij1234567890');
      expect(slug).toHaveLength(20);
    });

    it('>20 字符截断到 17 + SHA1 前 3 位（稳定 + 唯一）', () => {
      const nick = 'a-very-long-mail-nickname-that-exceeds-twenty-chars';
      const slug1 = svc.normalizeEmployeeSlug(nick);
      const slug2 = svc.normalizeEmployeeSlug(nick);
      expect(slug1).toHaveLength(20);
      expect(slug1).toBe(slug2); // 同输入稳定
      expect(slug1.slice(0, 17)).toBe('a-very-long-mail-');
    });

    it('不同长名生成不同后缀（碰撞低）', () => {
      const slug1 = svc.normalizeEmployeeSlug('A-Very-Long-Name-Alice');
      const slug2 = svc.normalizeEmployeeSlug('A-Very-Long-Name-Bob');
      expect(slug1).not.toBe(slug2);
      expect(slug1.slice(0, 17)).toBe(slug2.slice(0, 17)); // 前缀相同
    });

    it('中文字符全部变 - 后合并', () => {
      // 张三 → 全转 - 后去首尾，结果空字符串（应用层需走"加数字后缀"分支）
      expect(svc.normalizeEmployeeSlug('张三')).toBe('');
    });
  });

  describe('validateAppSlug', () => {
    it('合法 slug 通过', () => {
      expect(svc.validateAppSlug('birthday-reminder')).toEqual({ ok: true });
      expect(svc.validateAppSlug('abc')).toEqual({ ok: true });
      expect(svc.validateAppSlug('a-b-c-d-e-f-g-h-i-j-k')).toEqual({ ok: true });
    });

    it('长度 < 3 不合规', () => {
      expect(svc.validateAppSlug('ab').ok).toBe(false);
      expect(svc.validateAppSlug('a').ok).toBe(false);
    });

    it('长度 > 22 不合规', () => {
      expect(svc.validateAppSlug('a'.repeat(23)).ok).toBe(false);
    });

    it('首尾 - 不合规', () => {
      expect(svc.validateAppSlug('-birthday').ok).toBe(false);
      expect(svc.validateAppSlug('birthday-').ok).toBe(false);
    });

    it('含大写 / 特殊字符不合规', () => {
      expect(svc.validateAppSlug('Birthday-Reminder').ok).toBe(false);
      expect(svc.validateAppSlug('birthday_reminder').ok).toBe(false);
      expect(svc.validateAppSlug('birthday!').ok).toBe(false);
    });

    it('保留字命中返回 reserved 错误', () => {
      const result = svc.validateAppSlug('admin');
      expect(result.ok).toBe(false);
      if (!result.ok) {
        expect(result.reason).toContain('保留字');
      }
    });

    it('所有保留字都被拒', () => {
      const reservedSamples = [
        'admin', 'api', 'auth', 'login', 'logout',
        'mcp', 'oauth', 'sso', 'apps', 'www',
      ];
      for (const slug of reservedSamples) {
        const result = svc.validateAppSlug(slug);
        expect(result.ok).toBe(false);
      }
    });
  });
});
