/**
 * Auth access helpers.
 *
 * Sections:
 *  1. Pure case-access logic — no DB calls.
 *  2. Affiliate role derivation — DB query, cached per-request via user-cache.
 */

import type { User } from '@/server/auth/session.js';
import { ForbiddenError } from '@/server/middleware/session.js';
import type { TransactionCaseRow } from '@/server/db/queries/support-cases.js';
import { sql } from 'drizzle-orm';
import type { DrizzleClient } from '@/server/db/client.js';

// ---------------------------------------------------------------------------
// Case-access
// ---------------------------------------------------------------------------

export type CaseRole = 'admin' | 'plaintiff' | 'vendor';

// ---------------------------------------------------------------------------
// Affiliate role derivation
// ---------------------------------------------------------------------------

export type Role = 'admin' | 'user' | 'vendor' | 'affiliate';

/**
 * Query whether a user has an active affiliate_enrollments row.
 * Result is cached per-request via middleware context — do not call
 * this directly in hot paths; use locals.isAffiliate instead.
 */
export async function isActiveAffiliate(db: DrizzleClient, userId: string): Promise<boolean> {
  const result = (await db.execute(
    sql`SELECT 1 FROM affiliate_enrollments WHERE user_id = ${userId} AND status = 'active' LIMIT 1`,
  )) as { rows: unknown[] };
  return (result.rows?.length ?? 0) > 0;
}

/**
 * Resolve all roles for a user, including derived vendor and affiliate roles.
 * Called selectively in middleware for non-API paths (mirrors isVendor pattern).
 */
export async function resolveRoles(
  db: DrizzleClient,
  userId: string,
  isAdmin: boolean,
  isVendor: boolean,
): Promise<Role[]> {
  const roles: Role[] = ['user'];
  if (isAdmin) roles.push('admin');
  if (isVendor) roles.push('vendor');
  if (await isActiveAffiliate(db, userId)) roles.push('affiliate');
  return roles;
}

/**
 * Determine `user`'s role on `caseRow`.
 *
 * @param user - Authenticated user (FROZEN check already done by requireUser).
 * @param caseRow - Loaded transaction case row.
 * @param vendorOwnerUserId - ownerUserId of the vendor on the case (or null if
 *   vendor row could not be resolved — treated as no vendor match).
 * @returns The user's role on the case.
 * @throws {ForbiddenError} with code 'CASE_ACCESS_DENIED' if user is a stranger.
 */
export function determineCaseRole(
  user: User,
  caseRow: TransactionCaseRow,
  vendorOwnerUserId: string | null,
): CaseRole {
  if (user.isAdmin) return 'admin';
  if (caseRow.customerId === user.id) return 'plaintiff';
  if (vendorOwnerUserId !== null && vendorOwnerUserId === user.id) return 'vendor';
  throw new ForbiddenError('CASE_ACCESS_DENIED', 'Access to case denied');
}
