import { scoreSourceSchema } from "@domain/scores"
import { cuidSchema, issueIdSchema, SLUG_MAX_LENGTH } from "@domain/shared"
import { z } from "zod"
import { ISSUE_NAME_MAX_LENGTH, ISSUE_SOURCES, ISSUE_STATES } from "../constants.ts"

// ---------------------------------------------------------------------------
// IssueState
// ---------------------------------------------------------------------------

export const issueStateSchema = z.enum(ISSUE_STATES)
export type IssueState = z.infer<typeof issueStateSchema>

export const issueSourceSchema = z.enum(ISSUE_SOURCES)
export type IssueSource = z.infer<typeof issueSourceSchema>

export const IssueState = {
  New: "new",
  Escalating: "escalating",
  Ongoing: "ongoing",
  Resolved: "resolved",
  Regressed: "regressed",
  Ignored: "ignored",
} as const satisfies Record<string, IssueState>

// ---------------------------------------------------------------------------
// IssueCentroid
// ---------------------------------------------------------------------------

export const issueCentroidSchema = z.object({
  base: z.array(z.number()), // running vector sum of normalized, weighted, decayed member embeddings
  mass: z.number(), // running scalar mass of the centroid
  model: z.string(), // embedding model used to compute the centroid
  decay: z.number().positive(), // half-life in seconds
  weights: z.record(scoreSourceSchema, z.number().nonnegative()), // source weights used in centroid updates
})

export type IssueCentroid = z.infer<typeof issueCentroidSchema>

export const issueSchema = z.object({
  id: issueIdSchema, // CUID issue identifier
  organizationId: cuidSchema, // owning organization
  projectId: cuidSchema, // owning project
  slug: z.string().min(1).max(SLUG_MAX_LENGTH), // url-safe identifier derived from name; regenerated when name changes via `refreshIssueDetailsUseCase`. Unique per (organization_id, project_id).
  name: z.string().min(1).max(ISSUE_NAME_MAX_LENGTH), // generated from clustered score feedback and related evaluation/annotation context; generic enough to represent the shared failure pattern across different backgrounds
  description: z.string().min(1), // generated from clustered score feedback; focused on the underlying problem rather than one specific conversation; helps both human understanding and BM25 matching
  source: issueSourceSchema, // provenance of the first creating score
  centroid: issueCentroidSchema, // running weighted sum of clustered score feedback embeddings; drives derived pgvector semantic matching.
  clusteredAt: z.date(), // last time the centroid/cluster state was refreshed; authoritative decay anchor (not updatedAt)
  escalatedAt: z.date().nullable(), // DORMANT: not maintained by the system. "Currently escalating" is derived from open `alert_incidents` rows. Kept on the entity for backward compatibility; always null in practice.
  resolvedAt: z.date().nullable(), // issue resolved manually
  ignoredAt: z.date().nullable(), // issue ignored manually
  createdAt: z.date(), // issue creation time
  updatedAt: z.date(), // issue update time
})

export type Issue = z.infer<typeof issueSchema>
