import { Client, NoSuchObjectError } from 'ldapts';
import type { TeamDirectory } from './types';

export interface LdapConfig {
  url: string;
  baseDn: string;
}

export class LdapTeamDirectory implements TeamDirectory {
  constructor(private config: LdapConfig) {}

  async getTeamsForUser(username: string, candidateTeams: string[]): Promise<string[]> {
    const client = new Client({ url: this.config.url });
    const matchedTeams: string[] = [];
    const targetDn = `uid=${username},ou=People,${this.config.baseDn}`;

    try {
      await client.bind('', '');
      for (const team of candidateTeams) {
        try {
          const { searchEntries } = await client.search(`cn=${team},ou=Group,${this.config.baseDn}`, {
            scope: 'base',
            filter: '(objectClass=*)',
            attributes: ['uniqueMember'],
          });
          const entry = searchEntries[0];
          if (!entry) continue;
          const rawMembers = entry.uniqueMember;
          const members = Array.isArray(rawMembers) ? rawMembers : rawMembers ? [rawMembers] : [];
          if (members.includes(targetDn)) {
            matchedTeams.push(team);
          }
        } catch (err) {
          if (err instanceof NoSuchObjectError) {
            // Group doesn't exist (yet) -- treat as "not a member of it",
            // not a hard error. New teams get created over time.
            continue;
          }
          // Any other LDAP error (connection drop, timeout, protocol error,
          // etc.) is a genuine failure -- propagate it rather than silently
          // treating it the same as "group doesn't exist".
          throw err;
        }
      }
    } finally {
      await client.unbind();
    }

    return matchedTeams;
  }
}
