import type { CapMode } from '@prisma/client'
import type { PolicyResolution } from '@/types/competition'
import type { MemberContext } from './competition-context'

// ============================================================================
// System Defaults (Layer 1)
// ============================================================================

export const SYSTEM_DEFAULT_CAP = 15
export const SYSTEM_DEFAULT_CAP_MODE: CapMode = 'SOFT'
export const SYSTEM_DEFAULT_SOFT_BUFFER = 2

// ============================================================================
// Effective Cap Resolution (5-layer precedence)
// ============================================================================

/**
 * Resolves the effective assignment cap for a jury member.
 *
 * Precedence (first non-null wins):
 *   Layer 4b: selfServiceCap (bounded by admin max, only if allowJurorCapAdjustment)
 *   Layer 4a: maxAssignmentsOverride (admin per-member override)
 *   Layer 3:  juryGroup.defaultMaxAssignments
 *   Layer 1:  SYSTEM_DEFAULT_CAP (15)
 */
export function resolveEffectiveCap(ctx: MemberContext): PolicyResolution<number> {
  const group = ctx.juryGroup

  // Layer 4b: Self-service cap (juror-set during onboarding)
  if (group?.allowJurorCapAdjustment && ctx.member.selfServiceCap != null) {
    const adminMax =
      ctx.member.maxAssignmentsOverride
      ?? group.defaultMaxAssignments
      ?? SYSTEM_DEFAULT_CAP
    const bounded = Math.min(ctx.member.selfServiceCap, adminMax)
    return {
      value: bounded,
      source: 'member',
      explanation: `Self-service cap ${ctx.member.selfServiceCap} (bounded to ${adminMax})`,
    }
  }

  // Layer 4a: Admin per-member override
  if (ctx.member.maxAssignmentsOverride != null) {
    return {
      value: ctx.member.maxAssignmentsOverride,
      source: 'member',
      explanation: `Admin per-member override: ${ctx.member.maxAssignmentsOverride}`,
    }
  }

  // Layer 3: Jury group default
  if (group) {
    return {
      value: group.defaultMaxAssignments,
      source: 'jury_group',
      explanation: `Jury group "${group.name}" default: ${group.defaultMaxAssignments}`,
    }
  }

  // Layer 1: System default
  return {
    value: SYSTEM_DEFAULT_CAP,
    source: 'system',
    explanation: `System default: ${SYSTEM_DEFAULT_CAP}`,
  }
}

// ============================================================================
// Effective Cap Mode Resolution
// ============================================================================

/**
 * Resolves the effective cap mode for a jury member.
 *
 * Precedence:
 *   Layer 4a: capModeOverride (admin per-member)
 *   Layer 3:  juryGroup.defaultCapMode
 *   Layer 1:  SYSTEM_DEFAULT_CAP_MODE (SOFT)
 */
export function resolveEffectiveCapMode(ctx: MemberContext): PolicyResolution<CapMode> {
  // Layer 4a: Admin per-member override
  if (ctx.member.capModeOverride != null) {
    return {
      value: ctx.member.capModeOverride,
      source: 'member',
      explanation: `Admin per-member cap mode override: ${ctx.member.capModeOverride}`,
    }
  }

  // Layer 3: Jury group default
  if (ctx.juryGroup) {
    return {
      value: ctx.juryGroup.defaultCapMode,
      source: 'jury_group',
      explanation: `Jury group "${ctx.juryGroup.name}" default: ${ctx.juryGroup.defaultCapMode}`,
    }
  }

  // Layer 1: System default
  return {
    value: SYSTEM_DEFAULT_CAP_MODE,
    source: 'system',
    explanation: `System default: ${SYSTEM_DEFAULT_CAP_MODE}`,
  }
}

// ============================================================================
// Effective Soft Cap Buffer Resolution
// ============================================================================

/**
 * Resolves the effective soft cap buffer.
 * Only meaningful when capMode is SOFT.
 *
 * Precedence:
 *   Layer 3: juryGroup.softCapBuffer
 *   Layer 1: SYSTEM_DEFAULT_SOFT_BUFFER (2)
 */
export function resolveEffectiveSoftCapBuffer(
  ctx: MemberContext,
): PolicyResolution<number> {
  if (ctx.juryGroup) {
    return {
      value: ctx.juryGroup.softCapBuffer,
      source: 'jury_group',
      explanation: `Jury group "${ctx.juryGroup.name}" buffer: ${ctx.juryGroup.softCapBuffer}`,
    }
  }

  return {
    value: SYSTEM_DEFAULT_SOFT_BUFFER,
    source: 'system',
    explanation: `System default buffer: ${SYSTEM_DEFAULT_SOFT_BUFFER}`,
  }
}

// ============================================================================
// Effective Category Bias Resolution
// ============================================================================

/**
 * Resolves the effective category bias (startup ratio) for a jury member.
 *
 * Precedence:
 *   Layer 4b: selfServiceRatio (if allowJurorRatioAdjustment)
 *   Layer 4a: preferredStartupRatio (admin per-member)
 *   Layer 3:  juryGroup.defaultCategoryQuotas (derived ratio)
 *   Default:  null (no preference)
 */
export function resolveEffectiveCategoryBias(
  ctx: MemberContext,
): PolicyResolution<Record<string, number> | null> {
  const group = ctx.juryGroup

  // Layer 4b: Self-service ratio
  if (group?.allowJurorRatioAdjustment && ctx.member.selfServiceRatio != null) {
    const ratio = ctx.member.selfServiceRatio
    return {
      value: { STARTUP: ratio, BUSINESS_CONCEPT: 1 - ratio },
      source: 'member',
      explanation: `Self-service ratio: ${Math.round(ratio * 100)}% startup`,
    }
  }

  // Layer 4a: Admin per-member preferred ratio
  if (ctx.member.preferredStartupRatio != null) {
    const ratio = ctx.member.preferredStartupRatio
    return {
      value: { STARTUP: ratio, BUSINESS_CONCEPT: 1 - ratio },
      source: 'member',
      explanation: `Admin-set ratio: ${Math.round(ratio * 100)}% startup`,
    }
  }

  // Layer 3: Jury group default category quotas (derive ratio from quotas)
  if (group?.categoryQuotasEnabled && group.defaultCategoryQuotas) {
    const quotas = group.defaultCategoryQuotas as Record<
      string,
      { min: number; max: number }
    >
    const totalMax = Object.values(quotas).reduce((sum, q) => sum + q.max, 0)
    if (totalMax > 0) {
      const bias: Record<string, number> = {}
      for (const [cat, q] of Object.entries(quotas)) {
        bias[cat] = q.max / totalMax
      }
      return {
        value: bias,
        source: 'jury_group',
        explanation: `Derived from group category quotas`,
      }
    }
  }

  // No preference
  return {
    value: null,
    source: 'system',
    explanation: 'No category bias configured',
  }
}

// ============================================================================
// Aggregate Policy Evaluation
// ============================================================================

export type AssignmentPolicyResult = {
  effectiveCap: PolicyResolution<number>
  effectiveCapMode: PolicyResolution<CapMode>
  softCapBuffer: PolicyResolution<number>
  categoryBias: PolicyResolution<Record<string, number> | null>
  canAssignMore: boolean
  remainingCapacity: number
  isOverCap: boolean
  overCapBy: number
}

/**
 * Evaluates all assignment policies for a member in one call.
 * Returns resolved values with provenance plus computed flags.
 */
export function evaluateAssignmentPolicy(
  ctx: MemberContext,
): AssignmentPolicyResult {
  const effectiveCap = resolveEffectiveCap(ctx)
  const effectiveCapMode = resolveEffectiveCapMode(ctx)
  const softCapBuffer = resolveEffectiveSoftCapBuffer(ctx)
  const categoryBias = resolveEffectiveCategoryBias(ctx)

  const cap = effectiveCap.value
  const mode = effectiveCapMode.value
  const buffer = softCapBuffer.value
  const count = ctx.currentAssignmentCount

  const isOverCap = count > cap
  const overCapBy = Math.max(0, count - cap)
  const remainingCapacity =
    mode === 'NONE'
      ? Infinity
      : mode === 'SOFT'
        ? Math.max(0, cap + buffer - count)
        : Math.max(0, cap - count)

  const canAssignMore =
    mode === 'NONE'
      ? true
      : mode === 'SOFT'
        ? count < cap + buffer
        : count < cap

  return {
    effectiveCap,
    effectiveCapMode,
    softCapBuffer,
    categoryBias,
    canAssignMore,
    remainingCapacity,
    isOverCap,
    overCapBy,
  }
}
