import { findByUserIdWithPassword, findAuthContext } from '../repositories/employee.repo.js';
import { findByEmployeeId as findStageTransitions } from '../repositories/employeeStageTransition.repo.js';
import { comparePassword } from '../utils/hash.js';
import { signToken, type JwtPayload } from '../utils/jwt.js';
import { UnauthorizedError } from '../utils/errors.js';
import type { LoginResult, AuthUser } from '../types/index.js';

export async function login(identifier: string, password: string, rememberMe: boolean): Promise<LoginResult> {
  const employee = await findByUserIdWithPassword(identifier);
  if (!employee) throw new UnauthorizedError('Invalid credentials');
  if (!employee.auth_enabled) throw new UnauthorizedError('Account disabled');
  if (!employee.password_hash) throw new UnauthorizedError('Account not configured for login');

  const valid = await comparePassword(password, employee.password_hash);
  if (!valid) throw new UnauthorizedError('Invalid credentials');

  // Resolves role + per-employee grant/deny overrides together (the same
  // path every subsequent authenticated request uses via authenticate.ts) —
  // building permissions from role.permissions alone here would silently
  // drop any override, so the freshly-issued session/token would never
  // reflect it even though later requests would enforce it correctly.
  const ctx = await findAuthContext(employee.id);
  if (!ctx) throw new UnauthorizedError('Account no longer has access');

  const permissions = ctx.permissions === '*' ? ['*'] : ctx.permissions;
  const stageTransitions = await findStageTransitions(employee.id);

  const user: AuthUser = {
    id: employee.id,
    name: employee.name,
    email: employee.email ?? employee.user_id ?? '',
    role: ctx.role_name,
    permissions,
    stageTransitions,
    pendingDeliveryStageId: ctx.pending_delivery_stage_id,
  };

  const jwtPayload: JwtPayload = {
    sub: employee.id,
    role: ctx.role_name,
    permissions,
  };

  const token = signToken(jwtPayload, rememberMe);

  return { user, token };
}

// Used by GET /api/auth/session — re-resolves permissions the same way
// findAuthContext does (role + overrides), not just the role's own set, so
// a permission change takes effect for the frontend's cached user object as
// soon as the session is re-checked, not only on the next full login.
export async function getSessionUser(employeeId: string, email?: string): Promise<AuthUser | null> {
  const ctx = await findAuthContext(employeeId);
  if (!ctx) return null;
  return {
    id: ctx.id,
    name: ctx.name,
    email: email ?? '',
    role: ctx.role_name,
    permissions: ctx.permissions === '*' ? ['*'] : ctx.permissions,
    stageTransitions: await findStageTransitions(employeeId),
    pendingDeliveryStageId: ctx.pending_delivery_stage_id,
  };
}
