/**
 * Centralized access decision for an SSH connection.
 *
 * Design rationale (rev 4):
 *   resolveConnection() (in connection-repo) is a raw lookup with NO access
 *   check. This function is the SINGLE gate that callers MUST consult before
 *   exposing or using a connection. Splitting raw lookup from access decision
 *   means a granted user can be enumerated by their grant without first
 *   passing an owner-only getById check.
 *
 *   Order of decision:
 *     1. connection is disabled         → deny
 *     2. caller owns it                 → allow (via='owner')
 *     3. caller is admin AND
 *        adminBypassesGrants is true    → allow (via='admin')
 *     4. active grant exists for the
 *        (user|org, piece) tuple        → allow (via='grant')
 *     5. otherwise                      → deny
 *
 *   Disabled connections deny EVERYONE, including the owner — by-design,
 *   so that admin-disabled connections can't be used until an admin re-enables.
 *
 * Plan: docs/superpowers/plans/2026-05-12-ssh-tool-integration.md (Phase 1).
 */
import type { SshConnection } from './connection-repo.js';
import type { SshGrant, SshGrantsRepo } from './grants-repo.js';

export type AccessVia = 'owner' | 'admin' | 'grant';

export type AccessDenyReason = 'disabled' | 'no_grant';

export interface AccessDecision {
  allowed: boolean;
  via?: AccessVia;
  reason?: AccessDenyReason;
  grant?: SshGrant;
}

export interface ResolveAccessArgs {
  connection: SshConnection;
  userId: string;
  isAdmin: boolean;
  pieceName: string;
  orgIds: string[];
  /** Defaults to new Date(). Used to evaluate grant expiry. */
  now?: Date;
}

export interface AccessConfig {
  /** When true, admins bypass the grant check (still audited at use sites). */
  adminBypassesGrants: boolean;
}

export interface SshAccessResolver {
  resolveAccess(args: ResolveAccessArgs): AccessDecision;
}

export function createAccessResolver(
  grantsRepo: SshGrantsRepo,
  config: AccessConfig,
): SshAccessResolver {
  return {
    resolveAccess(args) {
      // 1. Disabled connections deny everyone.
      if (!args.connection.enabled) {
        return { allowed: false, reason: 'disabled' };
      }
      // 2. Owner.
      if (args.connection.ownerId !== null && args.connection.ownerId === args.userId) {
        return { allowed: true, via: 'owner' };
      }
      // 3. Admin bypass (if configured).
      if (args.isAdmin && config.adminBypassesGrants) {
        return { allowed: true, via: 'admin' };
      }
      // 4. Active grant?
      const grant = grantsRepo.findActiveGrant({
        connectionId: args.connection.id,
        userId: args.userId,
        orgIds: args.orgIds,
        pieceName: args.pieceName,
        now: (args.now ?? new Date()).toISOString(),
      });
      if (grant) {
        return { allowed: true, via: 'grant', grant };
      }
      return { allowed: false, reason: 'no_grant' };
    },
  };
}
