import { HttpClient } from '@angular/common/http';
import { Injectable, inject } from '@angular/core';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { AdminInvitation, AdminUserRoleRecord, AdminSession, AdminUser, AdminUserAuditEntry, AdminUserScope, AdminUserStatus } from '../models/admin-user.model';
import { AdminUsersGateway } from './admin-users-gateway.interface';

/**
 * Contract: docs/backend/TRACK-S-SECURITY-RBAC-CONTRACT.md §8 (team
 * invite/list/role/revoke on /api/admin/v2/team). Sessions/audit/status
 * endpoints aren't individually specified - inferred as sub-resources of the
 * same collection, consistent with the contract's team/{userId} pattern.
 */
@Injectable({ providedIn: 'root' })
export class AdminUsersApiGateway implements AdminUsersGateway {
  private readonly http = inject(HttpClient);

  loadUsers(): Observable<AdminUser[]> {
    return this.http.get<AdminUser[]>('/api/admin/v2/team');
  }

  loadRoles(): Observable<AdminUserRoleRecord[]> {
    return this.http.get<AdminUserRoleRecord[]>('/api/admin/v2/team/roles');
  }

  loadInvitations(): Observable<AdminInvitation[]> {
    return this.http.get<AdminInvitation[]>('/api/admin/v2/team/invitations');
  }

  loadSessions(userId: string): Observable<AdminSession[]> {
    return this.http.get<AdminSession[]>(`/api/admin/v2/team/${encodeURIComponent(userId)}/sessions`);
  }

  loadAudit(userId: string): Observable<AdminUserAuditEntry[]> {
    return this.http.get<AdminUserAuditEntry[]>(`/api/admin/v2/audit`, { params: { actor: userId } });
  }

  setUserRole(userId: string, roleId: string): Observable<AdminUser | null> {
    return this.http.patch<AdminUser | null>(`/api/admin/v2/team/${encodeURIComponent(userId)}`, { role: roleId });
  }

  setUserStatus(userId: string, status: AdminUserStatus): Observable<AdminUser | null> {
    return this.http.patch<AdminUser | null>(`/api/admin/v2/team/${encodeURIComponent(userId)}/status`, { status });
  }

  inviteUser(email: string, roleId: string, scope: AdminUserScope): Observable<AdminInvitation> {
    // §8's example body is { email, role, marketplaceId } - `scope` here is
    // 'marketplace' | 'office', not an id, so it is sent as its own field
    // rather than forced into marketplaceId.
    return this.http.post<AdminInvitation>('/api/admin/v2/team/invite', { email, role: roleId, scope });
  }

  revokeInvitation(id: string): Observable<void> {
    return this.http
      .delete(`/api/admin/v2/team/invitations/${encodeURIComponent(id)}`)
      .pipe(map(() => undefined));
  }

  revokeSession(sessionId: string): Observable<void> {
    return this.http
      .delete(`/api/admin/v2/team/sessions/${encodeURIComponent(sessionId)}`)
      .pipe(map(() => undefined));
  }
}
