import { z } from 'zod';

export const COUNCIL_SCHEMA_VERSION = '1.0.0';
export const COUNCIL_PIPELINE_VERSION = '1.0.0';

export const councilGroupSchema = z.enum(['D', 'P']);
export type CouncilGroup = z.infer<typeof councilGroupSchema>;

export const stopReasonSchema = z.enum([
  'max_rounds',
  'convergence',
  'bridge_validation_failed',
  'grounding_failed',
  'meta_validation_failed',
]);

export const validationFailureReasonSchema = z.enum([
  'schema_invalid',
  'unknown_id',
  'cap_exceeded',
  'repair_failed',
  'parse_failed',
]);

export const droppedReasonSchema = z.enum([
  'cap_top_ideas',
  'cap_field_bullets',
  'cap_entry_chars',
  'cap_total_chars',
  'invalid_reference',
  'grounding_failed',
]);

export const rejectionReasonCodeSchema = z.enum([
  'low_score',
  'high_risk',
  'insufficient_grounding',
  'duplicate',
  'out_of_scope',
  'unknown_id',
  'other',
]);

const schemaVersionField = z.literal(COUNCIL_SCHEMA_VERSION);

export const ideaContentSchema = z.object({
  title: z.string().min(1),
  hypothesis: z.string().min(1),
  mechanism: z.string().min(1),
  expected_outcome: z.string().min(1),
}).strict();

export const ideaGroundingSchema = z.object({
  mve: z.string().min(1),
  constraints: z.array(z.string().min(1)).min(1),
  falsifiability_checks: z.array(z.string().min(1)).min(1),
}).strict();

export const ideaCardSchema = z.object({
  schema_version: schemaVersionField,
  idea_id: z.string().min(1),
  group: councilGroupSchema,
  round: z.number().int().min(1),
  content: ideaContentSchema,
  grounding: ideaGroundingSchema.optional(),
  grounding_failed: z.boolean().optional(),
}).strict();

export const scoreSetSchema = z.object({
  novelty: z.number().int().min(0).max(100),
  feasibility: z.number().int().min(0).max(100),
  impact: z.number().int().min(0).max(100),
  testability: z.number().int().min(0).max(100),
}).strict();

export const ideaAssessmentSchema = z.object({
  schema_version: schemaVersionField,
  idea_id: z.string().min(1),
  scores: scoreSetSchema,
  decision: z.enum(['shortlist', 'hold', 'reject']),
  notes: z.string().min(1),
}).strict();

export const bridgeIdeaSchema = z.object({
  idea_id: z.string().min(1),
  mechanism: z.string().min(1),
  rationale: z.string().min(1),
}).strict();

export const bridgePacketSchema = z.object({
  schema_version: schemaVersionField,
  from_group: councilGroupSchema,
  to_group: councilGroupSchema,
  round: z.number().int().min(1),
  top_ideas: z.array(bridgeIdeaSchema),
  assumptions: z.array(z.string().min(1)),
  risks: z.array(z.string().min(1)),
  asks: z.array(z.string().min(1)),
  what_to_steal: z.array(z.string().min(1)),
}).strict();

export const councilBriefSchema = z.object({
  schema_version: schemaVersionField,
  group: councilGroupSchema,
  round: z.number().int().min(1),
  ideas: z.array(ideaCardSchema),
  assessments: z.array(ideaAssessmentSchema),
  shortlist: z.array(z.string().min(1)),
  assumptions: z.array(z.string().min(1)),
  risks: z.array(z.string().min(1)),
  asks: z.array(z.string().min(1)),
  what_to_steal: z.array(z.string().min(1)),
  convergence_signal: z.boolean(),
  novelty_score: z.number().int().min(0).max(100),
  repetition_rate: z.number().int().min(0).max(100),
}).strict();

export const councilDiffSchema = z.object({
  schema_version: schemaVersionField,
  group: councilGroupSchema,
  from_round: z.number().int().min(1),
  to_round: z.number().int().min(1),
  idea_added: z.array(z.string().min(1)),
  idea_removed: z.array(z.string().min(1)),
  shortlist_added: z.array(z.string().min(1)),
  shortlist_removed: z.array(z.string().min(1)),
  score_changes: z.array(z.object({
    idea_id: z.string().min(1),
    from_total: z.number().int(),
    to_total: z.number().int(),
  }).strict()),
  assumptions_added: z.array(z.string().min(1)),
  assumptions_removed: z.array(z.string().min(1)),
  mve_changed: z.array(z.string().min(1)),
}).strict();

export const mergeRecordSchema = z.object({
  sources: z.array(z.string().min(1)).min(2),
  result_title: z.string().min(1),
  rationale: z.string().min(1),
}).strict();

export const metaSelectionSchema = z.object({
  schema_version: schemaVersionField,
  selected_primary: z.array(z.string().min(1)),
  selected_secondary: z.array(z.string().min(1)),
  merges: z.array(mergeRecordSchema).optional(),
  rejections: z.array(z.object({
    idea_id: z.string().min(1),
    reason_code: rejectionReasonCodeSchema,
  }).strict()),
  open_questions: z.array(z.string().min(1)),
  next_experiments: z.array(z.string().min(1)),
}).strict();

export const councilTraceEventSchema = z.object({
  schema_version: schemaVersionField,
  event_id: z.string().min(1),
  phase_index: z.number().int().min(1),
  call_id: z.string().min(1),
  group: councilGroupSchema.optional(),
  round: z.number().int().min(1).optional(),
  prompt_payload_hash: z.string().length(64),
  artifact_hash: z.string().length(64).optional(),
  token_usage: z.object({
    inputTokens: z.number().int().min(0),
    outputTokens: z.number().int().min(0),
  }).strict().optional(),
  latency_ms: z.number().int().min(0).optional(),
  dropped_reason: droppedReasonSchema.optional(),
  validation_failure: validationFailureReasonSchema.optional(),
}).strict();

export const councilConversationTurnSchema = z.object({
  schema_version: schemaVersionField,
  phase_index: z.number().int().min(1),
  call_id: z.string().min(1),
  agent: z.string().min(1),
  tier: z.enum(['fast', 'default', 'complex', 'local']),
  group: councilGroupSchema.optional(),
  round: z.number().int().min(1).optional(),
  prompt_payload: z.record(z.string(), z.unknown()),
  response: z.string(),
  usage: z.object({
    inputTokens: z.number().int().min(0),
    outputTokens: z.number().int().min(0),
  }).strict(),
}).strict();

export const stopSnapshotSchema = z.object({
  stop_reason: stopReasonSchema,
  round_reached: z.number().int().min(1),
  final_shortlist_D: z.array(z.string().min(1)),
  final_shortlist_P: z.array(z.string().min(1)),
  bridge_validated: z.boolean(),
  grounding_failures_count: z.number().int().min(0),
}).strict();

export const councilRunResultSchema = z.object({
  pipeline_version: z.literal(COUNCIL_PIPELINE_VERSION),
  input_hash: z.string().length(64),
  brief_D_v1: councilBriefSchema,
  brief_P_v1: councilBriefSchema,
  brief_D_v2: councilBriefSchema,
  brief_P_v2: councilBriefSchema,
  diff_D: councilDiffSchema,
  diff_P: councilDiffSchema,
  bridge_D_to_P: bridgePacketSchema,
  bridge_P_to_D: bridgePacketSchema,
  meta: metaSelectionSchema,
  stop_snapshot: stopSnapshotSchema,
  trace: z.array(councilTraceEventSchema),
  conversations: z.array(councilConversationTurnSchema),
}).strict();

export const councilRunInputSchema = z.object({
  task: z.string().min(1),
  constraints: z.union([z.string().min(1), z.record(z.string(), z.unknown())]).optional(),
  success_definition: z.string().min(1).optional(),
  budget: z.record(z.string(), z.unknown()).optional(),
  timebox: z.union([z.string().min(1), z.number().positive()]).optional(),
  output_format: z.string().min(1).optional(),
  max_rounds: z.number().int().min(1).max(6).optional(),
  session_id: z.string().min(1).optional(),
}).strict();

export const ideationOutputSchema = z.object({
  ideas: z.array(ideaContentSchema).min(1),
}).strict();

export const assessmentOutputSchema = z.object({
  assessments: z.array(z.object({
    idea_id: z.string().min(1),
    scores: scoreSetSchema,
    decision: z.enum(['shortlist', 'hold', 'reject']),
    notes: z.string().min(1),
  }).strict()),
  assumptions: z.array(z.string().min(1)),
  risks: z.array(z.string().min(1)),
  asks: z.array(z.string().min(1)),
  what_to_steal: z.array(z.string().min(1)),
  convergence_signal: z.boolean(),
  novelty_score: z.number().int().min(0).max(100),
  repetition_rate: z.number().int().min(0).max(100),
}).strict();

export const groundingOutputSchema = z.object({
  grounded: z.array(z.object({
    idea_id: z.string().min(1),
    mve: z.string().min(1),
    constraints: z.array(z.string().min(1)).min(1),
    falsifiability_checks: z.array(z.string().min(1)).min(1),
  }).strict()),
}).strict();

export type StopReason = z.infer<typeof stopReasonSchema>;
export type ValidationFailureReason = z.infer<typeof validationFailureReasonSchema>;
export type DroppedReason = z.infer<typeof droppedReasonSchema>;
export type IdeaCard = z.infer<typeof ideaCardSchema>;
export type IdeaAssessment = z.infer<typeof ideaAssessmentSchema>;
export type BridgePacket = z.infer<typeof bridgePacketSchema>;
export type CouncilBrief = z.infer<typeof councilBriefSchema>;
export type CouncilDiff = z.infer<typeof councilDiffSchema>;
export type CouncilRunInput = z.infer<typeof councilRunInputSchema>;
export type CouncilRunResult = z.infer<typeof councilRunResultSchema>;
export type CouncilTraceEvent = z.infer<typeof councilTraceEventSchema>;
export type CouncilConversationTurn = z.infer<typeof councilConversationTurnSchema>;
export type MetaSelection = z.infer<typeof metaSelectionSchema>;
