import { sql } from 'drizzle-orm'
import {
  boolean, jsonb, numeric, pgEnum, pgPolicy, pgTable, text, timestamp, uuid,
} from 'drizzle-orm/pg-core'
import { criterion, requirement } from './solicitation.js'
import { response } from './response.js'

/**
 * Scoring. Fixed by #15.
 *
 * Two objects, deliberately separate: a suggestion is evidence with a proposal
 * attached; a score is a human act. There is no configuration that promotes
 * one to the other.
 */

/** What the model proposed. Never an award basis on its own. */
export const suggestion = pgTable('suggestion', {
  id: uuid('id').primaryKey().defaultRandom(),
  responseId: uuid('response_id').notNull().references(() => response.id),
  criterionId: uuid('criterion_id').notNull().references(() => criterion.id),
  proposedPoints: numeric('proposed_points', { precision: 8, scale: 2 }),
  /** The scale anchor matched, not just the integer — the anchor is load-bearing (#22). */
  anchorMatched: text('anchor_matched'),
  citations: jsonb('citations').$type<
    Array<{ documentId: string; page: number; span: { start: number; end: number } }>
  >().notNull().default([]),
  confidence: numeric('confidence', { precision: 4, scale: 3 }),
  /** Ordering only. Never gates, never auto-accepts. */
  modelVersion: text('model_version').notNull(),
  /** True where every mapped requirement was unanswered — no points are proposed. */
  noEvidenceFound: boolean('no_evidence_found').notNull().default(false),
  createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
}).enableRLS()

/**
 * The score of record. ALWAYS human-attributed. Never re-derived, so a model
 * upgrade mid-evaluation cannot move it.
 */
export const score = pgTable('score', {
  id: uuid('id').primaryKey().defaultRandom(),
  responseId: uuid('response_id').notNull().references(() => response.id),
  criterionId: uuid('criterion_id').notNull().references(() => criterion.id),
  points: numeric('points', { precision: 8, scale: 2 }).notNull(),
  committedBy: uuid('committed_by').notNull(),
  committedAt: timestamp('committed_at', { withTimezone: true }).notNull().defaultNow(),
  derivedFromSuggestionId: uuid('derived_from_suggestion_id').references(() => suggestion.id),
  /** Set when a rubric amendment voids this score; it must be re-committed. */
  voidedByAmendmentId: uuid('voided_by_amendment_id'),
}, () => [
  pgPolicy('score_read', {
    for: 'select',
    using: sql`class_released(release_level_for_response(response_id), 'own_scoring')`,
  }),
]).enableRLS()

/** Evaluated before scoring. A failure disqualifies regardless of points (#22, #15). */
export const gateResult = pgTable('gate_result', {
  responseId: uuid('response_id').notNull().references(() => response.id),
  requirementId: uuid('requirement_id').notNull().references(() => requirement.id),
  passed: boolean('passed').notNull(),
  computedAt: timestamp('computed_at', { withTimezone: true }).notNull().defaultNow(),
}).enableRLS()

/**
 * Amending the frozen criterion -> requirement mapping. Voids every committed
 * score under the old mapping and names its author (#15 decision 4).
 */
export const rubricAmendment = pgTable('rubric_amendment', {
  id: uuid('id').primaryKey().defaultRandom(),
  solicitationId: uuid('solicitation_id').notNull(),
  reason: text('reason').notNull(),
  voidedScoreIds: uuid('voided_score_ids').array().notNull().default([]),
  authoredBy: uuid('authored_by').notNull(),
  authoredAt: timestamp('authored_at', { withTimezone: true }).notNull().defaultNow(),
})
