/**
 * Service Provisioner Framework — Core Interface
 *
 * Each external service (Rocket.Chat, Gitea, Vaultwarden, Listmonk) implements
 * this interface. The UserProvisioningService orchestrator calls provisioners
 * through this contract, ensuring consistent lifecycle management.
 */

// Subset of Prisma User needed by provisioners (avoids Prisma dependency in interface)
export interface CMUser {
  id: string;
  email: string;
  name: string | null;
  role: string;
  roles: unknown; // JSON array of role strings
  status: string;
  permissions: Record<string, unknown> | null;
}

export type ProvisionTiming = 'lazy' | 'eager';

export interface ProvisionerConfig {
  /** Unique key identifying this service (e.g. 'rocketchat', 'gitea') */
  serviceKey: string;
  /** Display name for UI (e.g. 'Rocket.Chat', 'Gitea') */
  displayName: string;
  /** SiteSettings field that enables/disables this service's provisioning */
  featureFlag: string;
  /** Key prefix in User.permissions JSON (e.g. '_rcUserId', '_giteaUserId') */
  permissionsKey: string;
  /** Changemaker role → service-specific role(s) mapping */
  roleMap: Record<string, string[]>;
  /** Roles that should NOT be provisioned (e.g. TEMP users) */
  excludeRoles?: string[];
}

export type ProvisionStatus = 'synced' | 'pending' | 'error' | 'not_provisioned' | 'invited';

export interface ProvisionResult {
  success: boolean;
  serviceUserId?: string;
  /** Additional data to store in permissions JSON (e.g. username, invite date) */
  extraPermissions?: Record<string, unknown>;
  error?: string;
}

export interface ServiceProvisioningStatus {
  serviceKey: string;
  displayName: string;
  status: ProvisionStatus;
  serviceUserId?: string;
  lastError?: string;
  /** Extra info like username, invite date, etc. */
  details?: Record<string, unknown>;
}

/**
 * Interface that each service provisioner must implement.
 *
 * Provisioners handle:
 * - Creating accounts in external services when CM users are created
 * - Syncing user data (name, role) when CM users are updated
 * - Deactivating/removing accounts when CM users are deactivated
 * - Optionally generating SSO tokens for seamless login
 */
export interface ServiceProvisioner {
  /** Static configuration for this provisioner */
  readonly config: ProvisionerConfig;

  /**
   * Check if the external service is reachable and configured.
   * Called before provisioning attempts.
   */
  isAvailable(): Promise<boolean>;

  /**
   * Create an account in the external service for this CM user.
   * Should be idempotent — if user already exists, link and return success.
   */
  provision(user: CMUser): Promise<ProvisionResult>;

  /**
   * Sync user data (name, roles, status) to the external service.
   * Called when a CM user is updated.
   */
  syncUser(user: CMUser, serviceUserId: string): Promise<void>;

  /**
   * Deactivate or remove the user's account in the external service.
   * Called when a CM user is deactivated or deleted.
   */
  deactivate(serviceUserId: string): Promise<void>;

  /**
   * Optional: Generate an SSO/auth token for seamless login.
   * Used by services that support iframe embedding (e.g. Rocket.Chat).
   */
  getAuthToken?(user: CMUser, serviceUserId: string): Promise<string | null>;
}
