import { z } from 'zod'
import type { RoundType, AwardEligibilityMode, AwardScoringMode, AwardStatus } from '@prisma/client'

// ============================================================================
// Round-Type-Specific Zod Config Schemas
// ============================================================================
// Each RoundType has a dedicated config schema stored in Round.configJson.
// These replace the loosely-typed pipeline-wizard.ts configs with
// Zod-validated, compile-time-safe contracts.

// Shared fields that appear in "General Settings" for all round types
const generalSettingsFields = {
  startupAdvanceCount: z.number().int().nonnegative().optional(),
  conceptAdvanceCount: z.number().int().nonnegative().optional(),
  advanceMode: z.enum(['count', 'threshold']).default('count'),
  advanceScoreThreshold: z.number().min(0).max(10).optional(),
  gracePeriodHours: z.number().int().nonnegative().default(0),
}

// ─── 1. IntakeConfig ─────────────────────────────────────────────────────────

export const IntakeConfigSchema = z.object({
  ...generalSettingsFields,
  allowDrafts: z.boolean().default(true),
  draftExpiryDays: z.number().int().positive().default(30),

  acceptedCategories: z
    .array(z.enum(['STARTUP', 'BUSINESS_CONCEPT']))
    .default(['STARTUP', 'BUSINESS_CONCEPT']),

  maxFileSizeMB: z.number().int().positive().default(50),
  maxFilesPerSlot: z.number().int().positive().default(1),
  allowedMimeTypes: z.array(z.string()).default(['application/pdf']),

  lateSubmissionNotification: z.boolean().default(true),

  publicFormEnabled: z.boolean().default(false),
  customFields: z
    .array(
      z.object({
        id: z.string(),
        label: z.string(),
        type: z.enum(['text', 'textarea', 'select', 'checkbox', 'date']),
        required: z.boolean().default(false),
        options: z.array(z.string()).optional(),
      }),
    )
    .default([]),
})

export type IntakeConfig = z.infer<typeof IntakeConfigSchema>

// ─── 2. FilteringConfig ──────────────────────────────────────────────────────

export const FilteringConfigSchema = z.object({
  ...generalSettingsFields,
  rules: z
    .array(
      z.object({
        id: z.string(),
        name: z.string(),
        ruleType: z.enum(['FIELD_BASED', 'DOCUMENT_CHECK']),
        conditions: z.any(),
        action: z.enum(['PASS', 'REJECT', 'FLAG']),
      }),
    )
    .default([]),

  aiScreeningEnabled: z.boolean().default(true),
  aiCriteriaText: z.string().optional(),
  aiConfidenceThresholds: z
    .object({
      high: z.number().min(0).max(1).default(0.85),
      medium: z.number().min(0).max(1).default(0.6),
      low: z.number().min(0).max(1).default(0.4),
    })
    .default({ high: 0.85, medium: 0.6, low: 0.4 }),

  manualReviewEnabled: z.boolean().default(true),
  autoAdvanceEligible: z.boolean().default(false),
  duplicateDetectionEnabled: z.boolean().default(true),
  batchSize: z.number().int().positive().default(20),

  aiParseFiles: z.boolean().default(false),
})

export type FilteringConfig = z.infer<typeof FilteringConfigSchema>

// ─── 3. EvaluationConfig ─────────────────────────────────────────────────────

export const EvaluationConfigSchema = z.object({
  ...generalSettingsFields,
  requiredReviewsPerProject: z.number().int().positive().default(3),

  scoringMode: z.enum(['criteria', 'global', 'binary']).default('criteria'),
  perCategoryCriteria: z.boolean().default(false),
  requireFeedback: z.boolean().default(true),
  feedbackMinLength: z.number().int().nonnegative().default(0),
  requireAllCriteriaScored: z.boolean().default(true),

  requireDocumentUpload: z.boolean().default(false),

  coiRequired: z.boolean().default(true),

  peerReviewEnabled: z.boolean().default(false),
  showJurorProgressDashboard: z.boolean().default(false),
  anonymizationLevel: z
    .enum(['fully_anonymous', 'show_initials', 'named'])
    .default('fully_anonymous'),

  aiSummaryEnabled: z.boolean().default(false),
  generateAiShortlist: z.boolean().default(false),
  aiParseFiles: z.boolean().default(false),

  applicantVisibility: z
    .object({
      enabled: z.boolean().default(false),
      showGlobalScore: z.boolean().default(false),
      showCriterionScores: z.boolean().default(false),
      showFeedbackText: z.boolean().default(false),
      hideFromRejected: z.boolean().default(false),
    })
    .default({
      enabled: false,
      showGlobalScore: false,
      showCriterionScores: false,
      showFeedbackText: false,
      hideFromRejected: false,
    }),

  advancementMode: z
    .enum(['auto_top_n', 'admin_selection', 'ai_recommended'])
    .default('admin_selection'),
  advancementConfig: z
    .object({
      perCategory: z.boolean().default(true),
      startupCount: z.number().int().nonnegative().default(10),
      conceptCount: z.number().int().nonnegative().default(10),
      tieBreaker: z
        .enum(['admin_decides', 'highest_individual', 'revote'])
        .default('admin_decides'),
    })
    .optional(),

  // Whether the ranking dashboard ranks projects by juror-balanced (z-normalized)
  // average. Defaulting to true preserves existing behavior. Toggled per-round
  // from the dashboard side panel.
  useBalancedRanking: z.boolean().default(true),

  // Whether the project pass rate (yes/no advance vote) is harshness-corrected
  // before being fed into the composite ranking formula. When true, a "yes" from
  // a juror who rarely says yes weighs more than a "yes" from a lenient juror.
  // Toggled separately from useBalancedRanking; both default to true.
  useBalancedPassRate: z.boolean().default(true),

  // Ranking (Phase 1)
  rankingEnabled: z.boolean().default(false),
  rankingCriteria: z.string().optional(),
  autoRankOnComplete: z.boolean().default(false),

  // Ranking (Phase 2) — per-criterion weights for AI ranking
  criteriaWeights: z.record(z.string(), z.number().min(0).max(10)).optional(),

  // Ranking (Phase 3) — composite score formula weights
  scoreWeight: z.number().min(0).max(10).default(5),
  passRateWeight: z.number().min(0).max(10).default(5),
})

export type EvaluationConfig = z.infer<typeof EvaluationConfigSchema>

// ─── 4. SubmissionConfig ─────────────────────────────────────────────────────

export const SubmissionConfigSchema = z.object({
  ...generalSettingsFields,
  notifyEligibleTeams: z.boolean().default(true),
  lockPreviousWindows: z.boolean().default(true),
})

export type SubmissionConfig = z.infer<typeof SubmissionConfigSchema>

// ─── 5. MentoringConfig ──────────────────────────────────────────────────────

export const MentoringConfigSchema = z.object({
  ...generalSettingsFields,
  eligibility: z
    .enum(['all_advancing', 'requested_only', 'admin_selected'])
    .default('requested_only'),

  chatEnabled: z.boolean().default(true),
  fileUploadEnabled: z.boolean().default(true),
  fileCommentsEnabled: z.boolean().default(true),
  filePromotionEnabled: z.boolean().default(true),

  promotionTargetWindowId: z.string().optional(),
  autoAssignMentors: z.boolean().default(false),

  mentoringRequestDeadlineDays: z.number().int().positive().default(14),
  passThroughIfNoRequest: z.boolean().default(true),
})

export type MentoringConfig = z.infer<typeof MentoringConfigSchema>

// ─── 6. LiveFinalConfig ──────────────────────────────────────────────────────

export const LiveFinalConfigSchema = z.object({
  ...generalSettingsFields,
  juryVotingEnabled: z.boolean().default(true),
  votingMode: z.enum(['simple', 'criteria']).default('simple'),

  audienceVotingEnabled: z.boolean().default(false),
  audienceVoteWeight: z.number().min(0).max(1).default(0),
  audienceVotingMode: z
    .enum(['per_project', 'per_category', 'favorites'])
    .default('per_project'),
  audienceMaxFavorites: z.number().int().positive().default(3),
  audienceRequireIdentification: z.boolean().default(false),
  audienceRevealTiming: z
    .enum(['real_time', 'after_jury_scores', 'at_deliberation', 'never'])
    .default('at_deliberation'),

  deliberationEnabled: z.boolean().default(false),
  deliberationDurationMinutes: z.number().int().positive().default(30),
  showAudienceVotesToJury: z.boolean().default(false),

  presentationOrderMode: z
    .enum(['manual', 'random', 'score_based'])
    .default('manual'),
  presentationDurationMinutes: z.number().int().positive().default(15),
  qaDurationMinutes: z.number().int().nonnegative().default(5),

  revealPolicy: z.enum(['immediate', 'delayed', 'ceremony']).default('ceremony'),

  /** Controls whether observers can see live scores: realtime, after session completes, or never */
  observerScoreVisibility: z.enum(['realtime', 'after_completion', 'hidden']).default('after_completion'),
})

export type LiveFinalConfig = z.infer<typeof LiveFinalConfigSchema>

// ─── 7. DeliberationConfig ───────────────────────────────────────────────────

export const DeliberationConfigSchema = z.object({
  ...generalSettingsFields,
  juryGroupId: z.string(),

  mode: z
    .enum(['SINGLE_WINNER_VOTE', 'FULL_RANKING'])
    .default('SINGLE_WINNER_VOTE'),

  showCollectiveRankings: z.boolean().default(false),
  showPriorJuryData: z.boolean().default(false),

  tieBreakMethod: z
    .enum(['RUNOFF', 'ADMIN_DECIDES', 'SCORE_FALLBACK'])
    .default('ADMIN_DECIDES'),

  votingDuration: z.number().int().positive().default(60),
  topN: z.number().int().positive().default(3),
  allowAdminOverride: z.boolean().default(true),
})

export type DeliberationConfig = z.infer<typeof DeliberationConfigSchema>

// ============================================================================
// Config Map & Helpers
// ============================================================================

export type RoundConfigMap = {
  INTAKE: IntakeConfig
  FILTERING: FilteringConfig
  EVALUATION: EvaluationConfig
  SUBMISSION: SubmissionConfig
  MENTORING: MentoringConfig
  LIVE_FINAL: LiveFinalConfig
  DELIBERATION: DeliberationConfig
}

const schemaMap: Record<RoundType, z.ZodSchema> = {
  INTAKE: IntakeConfigSchema,
  FILTERING: FilteringConfigSchema,
  EVALUATION: EvaluationConfigSchema,
  SUBMISSION: SubmissionConfigSchema,
  MENTORING: MentoringConfigSchema,
  LIVE_FINAL: LiveFinalConfigSchema,
  DELIBERATION: DeliberationConfigSchema,
}

/**
 * Validates a configJson object against the Zod schema for the given RoundType.
 * Returns the parsed (with defaults applied) config or throws a ZodError.
 */
export function validateRoundConfig<T extends RoundType>(
  roundType: T,
  config: unknown,
): RoundConfigMap[T] {
  const schema = schemaMap[roundType]
  return schema.parse(config) as RoundConfigMap[T]
}

/**
 * Returns safe-parsed result (no throw) for config validation.
 */
export function safeValidateRoundConfig<T extends RoundType>(
  roundType: T,
  config: unknown,
): z.SafeParseReturnType<unknown, RoundConfigMap[T]> {
  const schema = schemaMap[roundType]
  return schema.safeParse(config) as z.SafeParseReturnType<
    unknown,
    RoundConfigMap[T]
  >
}

/**
 * Returns default config for the given RoundType with all defaults applied.
 * For DELIBERATION, a placeholder juryGroupId is used — caller must replace.
 */
export function defaultRoundConfig<T extends RoundType>(
  roundType: T,
): RoundConfigMap[T] {
  const defaults: Record<RoundType, () => unknown> = {
    INTAKE: () => IntakeConfigSchema.parse({}),
    FILTERING: () => FilteringConfigSchema.parse({}),
    EVALUATION: () => EvaluationConfigSchema.parse({}),
    SUBMISSION: () => SubmissionConfigSchema.parse({}),
    MENTORING: () => MentoringConfigSchema.parse({}),
    LIVE_FINAL: () => LiveFinalConfigSchema.parse({}),
    DELIBERATION: () =>
      DeliberationConfigSchema.parse({ juryGroupId: 'PLACEHOLDER' }),
  }
  return defaults[roundType]() as RoundConfigMap[T]
}

// ============================================================================
// Award Config Types
// ============================================================================
// Typed interfaces matching Prisma enums for award configuration.

export const AwardEligibilityModeSchema = z.enum(['SEPARATE_POOL', 'STAY_IN_MAIN'])
export const AwardScoringModeSchema = z.enum(['PICK_WINNER', 'RANKED', 'SCORED'])
export const AwardStatusSchema = z.enum([
  'DRAFT',
  'NOMINATIONS_OPEN',
  'VOTING_OPEN',
  'VOTING_CLOSED',
  'DECIDED',
  'ANNOUNCED',
])
export const AwardDecisionModeSchema = z.enum([
  'JURY_VOTE',
  'ADMIN_DECISION',
])

export const AwardConfigSchema = z.object({
  /** How eligible projects relate to the main competition track */
  eligibilityMode: AwardEligibilityModeSchema.default('STAY_IN_MAIN'),
  /** How the winner is determined */
  scoringMode: AwardScoringModeSchema.default('PICK_WINNER'),
  /** Who makes the final decision */
  decisionMode: AwardDecisionModeSchema.default('JURY_VOTE'),
  /** Max ranked picks for RANKED scoring mode */
  maxRankedPicks: z.number().int().positive().optional(),
  /** Whether AI evaluates eligibility */
  useAiEligibility: z.boolean().default(true),
  /** Plain-language criteria for AI interpretation */
  criteriaText: z.string().optional(),
})

export type AwardConfig = z.infer<typeof AwardConfigSchema>
