/**
 * Mosaic Native Kanban — frozen health/error contract v1.
 * Publication contract only; no runtime implementation is included here.
 *
 * PostgreSQL is the sole writable SOT. Public health DTOs are observations,
 * never write authority. Only an internal transaction-local proof produced by
 * the PostgreSQL adapter may authorize a mutation.
 */

export const KANBAN_CONTRACT_VERSION = '1.0.0' as const;

export const kanbanHealthStates = ['healthy', 'read-only-degraded', 'write-unavailable'] as const;
export type KanbanHealthState = (typeof kanbanHealthStates)[number];

interface KanbanHealthBaseV1 {
  contractVersion: typeof KANBAN_CONTRACT_VERSION;
  checkedAt: string;
  /** Observation expires at this RFC 3339 instant; it still never authorizes writes. */
  validUntil: string;
  policyRevision: string;
  reasons: string[];
}

export interface HealthyKanbanHealthResponseV1 extends KanbanHealthBaseV1 {
  state: 'healthy';
  readHealthProven: true;
  writeHealthProven: true;
}

export interface ReadOnlyDegradedKanbanHealthResponseV1 extends KanbanHealthBaseV1 {
  state: 'read-only-degraded';
  readHealthProven: true;
  writeHealthProven: false;
}

export interface WriteUnavailableKanbanHealthResponseV1 extends KanbanHealthBaseV1 {
  state: 'write-unavailable';
  readHealthProven: false;
  writeHealthProven: false;
}

/** Public, discriminated observation. Contradictory combinations are unrepresentable. */
export type KanbanHealthResponseV1 =
  | HealthyKanbanHealthResponseV1
  | ReadOnlyDegradedKanbanHealthResponseV1
  | WriteUnavailableKanbanHealthResponseV1;

/** Pure evaluation context. It cannot authorize a mutation. */
export interface KanbanEvaluationContextV1 {
  contractVersion: typeof KANBAN_CONTRACT_VERSION;
  workspaceId: string;
  correlationId: string;
  now: string;
  policyRevision: string;
  observedHealth: KanbanHealthResponseV1;
}

/**
 * Non-exported brand: public DTO deserialization cannot construct this type.
 * The PostgreSQL adapter mints it only after a fresh write probe inside the same
 * transaction and validates checkedAt <= now < validUntil and policy revision.
 */
declare const postgresWriteHealthProofBrand: unique symbol;
export interface PostgresWriteHealthProofV1 {
  readonly [postgresWriteHealthProofBrand]: true;
  readonly source: 'postgres-transaction-local-write-probe';
  readonly transactionId: string;
  readonly checkedAt: string;
  readonly validUntil: string;
  readonly policyRevision: string;
}

/** Internal mutation context; MUST NOT appear in REST/MCP/CLI request DTOs. */
export interface InternalKanbanMutationContextV1 {
  contractVersion: typeof KANBAN_CONTRACT_VERSION;
  workspaceId: string;
  correlationId: string;
  causationId?: string;
  idempotencyKey: string;
  now: string;
  expectedPolicyRevision: string;
  writeProof: PostgresWriteHealthProofV1;
}

interface MutationFailureBaseV1 {
  contractVersion: typeof KANBAN_CONTRACT_VERSION;
  retryable: false;
  requestOutcome: 'not_applied';
  idempotencyKey: string;
  correlationId: string;
  message: string;
}

/** KCR-016: code/state pairing is exact and cannot cross-map. */
export interface ReadOnlyWriteHealthDenialV1 extends MutationFailureBaseV1 {
  kind: 'deliberate_fail_closed_denial';
  code: 'KANBAN_WRITE_HEALTH_UNPROVEN';
  healthState: 'read-only-degraded';
  checkedAt: string;
}

export interface WriteUnavailableDenialV1 extends MutationFailureBaseV1 {
  kind: 'deliberate_fail_closed_denial';
  code: 'KANBAN_WRITE_UNAVAILABLE';
  healthState: 'write-unavailable';
  checkedAt: string;
}

export type DeliberateWriteDenialV1 = ReadOnlyWriteHealthDenialV1 | WriteUnavailableDenialV1;

export const transportErrorCodes = [
  'GATEWAY_UNREACHABLE',
  'GATEWAY_TIMEOUT',
  'UPSTREAM_BAD_GATEWAY',
] as const;
export type TransportErrorCode = (typeof transportErrorCodes)[number];

/** Client-normalized transport uncertainty; never an authoritative 503 body. */
export interface RetryableTransportErrorV1 {
  contractVersion: typeof KANBAN_CONTRACT_VERSION;
  kind: 'retryable_transport_error';
  code: TransportErrorCode;
  retryable: true;
  requestOutcome: 'unknown';
  /** Retry MUST reuse this exact key. */
  idempotencyKey: string;
  correlationId: string;
  message: string;
}

export interface VersionConflictV1 {
  contractVersion: typeof KANBAN_CONTRACT_VERSION;
  kind: 'version_conflict';
  code: 'AGGREGATE_VERSION_CONFLICT';
  retryable: false;
  requestOutcome: 'not_applied';
  aggregateType: 'project' | 'mission' | 'milestone' | 'task' | 'change_proposal';
  aggregateId: string;
  expectedVersion: number;
  actualVersion: number;
  idempotencyKey: string;
  correlationId: string;
  message: string;
}

export type KanbanMutationFailureV1 =
  | DeliberateWriteDenialV1
  | RetryableTransportErrorV1
  | VersionConflictV1;

export const kanbanHealthCapabilities: Readonly<
  Record<KanbanHealthState, { canonicalReads: boolean; mutations: boolean }>
> = {
  healthy: { canonicalReads: true, mutations: true },
  'read-only-degraded': { canonicalReads: true, mutations: false },
  'write-unavailable': { canonicalReads: false, mutations: false },
};

/** Exact HTTP/error normalization freeze; 503, transport, and 409 cannot cross-map. */
export const kanbanFailureHttpMapV1 = {
  KANBAN_WRITE_HEALTH_UNPROVEN: {
    httpStatus: 503,
    kind: 'deliberate_fail_closed_denial',
    requestOutcome: 'not_applied',
    retryable: false,
  },
  KANBAN_WRITE_UNAVAILABLE: {
    httpStatus: 503,
    kind: 'deliberate_fail_closed_denial',
    requestOutcome: 'not_applied',
    retryable: false,
  },
  AGGREGATE_VERSION_CONFLICT: {
    httpStatus: 409,
    kind: 'version_conflict',
    requestOutcome: 'not_applied',
    retryable: false,
  },
  GATEWAY_UNREACHABLE: {
    httpStatus: 502,
    kind: 'retryable_transport_error',
    requestOutcome: 'unknown',
    retryable: true,
  },
  GATEWAY_TIMEOUT: {
    httpStatus: 504,
    kind: 'retryable_transport_error',
    requestOutcome: 'unknown',
    retryable: true,
  },
  UPSTREAM_BAD_GATEWAY: {
    httpStatus: 502,
    kind: 'retryable_transport_error',
    requestOutcome: 'unknown',
    retryable: true,
  },
} as const;

/**
 * Required negative contract tests:
 * - contradictory state/proof booleans fail type/schema validation;
 * - expired internal proof and policy mismatch deny before mutation;
 * - Valkey-only liveness cannot mint PostgresWriteHealthProofV1;
 * - public/caller-forged `healthy` cannot enter InternalKanbanMutationContextV1;
 * - authoritative 503, transport 502/504/timeout, and 409 mappings are exhaustive.
 */
