/** JSON-safe contracts for an eventual server-authoritative Tera session. */

export type RealtimeActorKind = "humanoid" | "dog" | "crow";
export type RealtimeVehicleKind = "model-x";
export type RealtimeAircraftKind = "electric-vtail";
export type RealtimeMemberRole = "visitor" | "member" | "admin";
export type RealtimeRevocationReason =
  | "signed-out"
  | "membership-revoked"
  | "session-replaced"
  | "protocol-violation"
  | "server-shutdown";

export interface CaliforniaTileInterest {
  kind: "california-tile";
  /** Discrete authored world grid, not web-map tiles. */
  x: number;
  y: number;
  level: number;
}

export interface CityInterest {
  kind: "city";
  cityId: "bay-area" | "socal";
}

export interface OfficeInterest {
  kind: "office";
  officeId: string;
}

export interface FloorInterest {
  kind: "floor";
  officeId: string;
  floorId: string;
}

export interface RoomInterest {
  kind: "room";
  officeId: string;
  floorId: string;
  roomId: string;
}

export type InterestCell =
  | CaliforniaTileInterest
  | CityInterest
  | OfficeInterest
  | FloorInterest
  | RoomInterest;

/** Monotonic within one server epoch and bounded to an unsigned 32-bit integer. */
export type RealtimeSequence = number;
/** Unix epoch milliseconds, serialized as a safe integer. */
export type RealtimeTimestamp = number;

export interface GeographicPose {
  space: "geographic";
  lat: number;
  lng: number;
  altitudeM: number;
  headingDeg: number;
  pitchDeg: number;
}

export interface LocalPose {
  space: "local";
  /** The smallest spatial cell whose coordinates define this pose. */
  cell: CityInterest | OfficeInterest | FloorInterest | RoomInterest;
  xM: number;
  yM: number;
  zM: number;
  headingDeg: number;
  pitchDeg: number;
}

export type SpatialPose = GeographicPose | LocalPose;

export interface PoseVelocity {
  xMps: number;
  yMps: number;
  zMps: number;
  yawDegPerSec: number;
}

interface EntityPoseSnapshotBase {
  sequence: RealtimeSequence;
  timestampMs: RealtimeTimestamp;
  pose: SpatialPose;
  velocity: PoseVelocity;
}

export interface ActorPoseSnapshot extends EntityPoseSnapshotBase {
  entity: "actor";
  actorId: string;
  kind: RealtimeActorKind;
}

export interface VehiclePoseSnapshot extends EntityPoseSnapshotBase {
  entity: "vehicle";
  vehicleId: string;
  kind: RealtimeVehicleKind;
  driverActorId: string | null;
  steering: number;
  wheelRadians: number;
}

/** Authoritative state needed to reproduce a piloted aircraft on another client. */
export interface AircraftPoseSnapshot extends EntityPoseSnapshotBase {
  entity: "aircraft";
  aircraftId: string;
  kind: RealtimeAircraftKind;
  pilotActorId: string;
  rollDeg: number;
  throttle: number;
  rollInput: number;
  pitchInput: number;
  yawInput: number;
  fanRadians: number;
}

export type EntityPoseSnapshot = ActorPoseSnapshot | VehiclePoseSnapshot | AircraftPoseSnapshot;

export interface JoinRequest {
  type: "join-request";
  protocolVersion: 1;
  requestId: string;
  actorId: string;
  resumeToken: string | null;
  lastReceivedSequence: RealtimeSequence | null;
  interests: readonly InterestCell[];
}

export interface JoinGrant {
  type: "join-grant";
  protocolVersion: 1;
  requestId: string;
  sessionId: string;
  actorId: string;
  role: RealtimeMemberRole;
  serverEpoch: string;
  serverTimeMs: RealtimeTimestamp;
  nextSequence: RealtimeSequence;
  resumeToken: string;
  interests: readonly InterestCell[];
  initial: readonly EntityPoseSnapshot[];
}

export interface ResumeRequest {
  type: "resume-request";
  protocolVersion: 1;
  requestId: string;
  sessionId: string;
  resumeToken: string;
  serverEpoch: string;
  lastReceivedSequence: RealtimeSequence;
  interests: readonly InterestCell[];
}

export interface ResumeGrant {
  type: "resume-grant";
  protocolVersion: 1;
  requestId: string;
  sessionId: string;
  serverEpoch: string;
  serverTimeMs: RealtimeTimestamp;
  nextSequence: RealtimeSequence;
  resumeToken: string;
  /** True means queued deltas bridge the requested sequence without a gap. */
  continuous: boolean;
  snapshot: readonly EntityPoseSnapshot[];
}

export interface PoseDelta {
  type: "pose-delta";
  protocolVersion: 1;
  serverEpoch: string;
  sequence: RealtimeSequence;
  timestampMs: RealtimeTimestamp;
  updates: readonly EntityPoseSnapshot[];
  removedEntityIds: readonly string[];
}

export interface MembershipRevoked {
  type: "membership-revoked";
  protocolVersion: 1;
  serverEpoch: string;
  sequence: RealtimeSequence;
  timestampMs: RealtimeTimestamp;
  sessionId: string;
  actorId: string;
  reason: RealtimeRevocationReason;
  reconnectAllowed: boolean;
}

export type ClientRealtimeMessage = JoinRequest | ResumeRequest;
export type ServerRealtimeMessage = JoinGrant | ResumeGrant | PoseDelta | MembershipRevoked;

export type RealtimeValidationResult<T> =
  | { ok: true; value: T }
  | { ok: false; error: string };

export interface MotionLimits {
  maximumHorizontalSpeedMps: number;
  maximumVerticalSpeedMps: number;
  maximumTurnRateDegPerSec: number;
  /** Allows quantization and packet jitter without permitting teleportation. */
  positionSlackM: number;
  minimumDeltaSeconds?: number;
  maximumDeltaSeconds?: number;
}

export type MotionValidationResult =
  | { ok: true; horizontalSpeedMps: number; verticalSpeedMps: number; turnRateDegPerSec: number }
  | {
      ok: false;
      reason: "identity-mismatch" | "space-mismatch" | "time-invalid" | "speed-exceeded";
    };

export interface InterpolationOptions {
  interpolationDelayMs?: number;
  maximumExtrapolationMs?: number;
  capacity?: number;
}

export type BufferedSampleMode = "exact" | "interpolated" | "extrapolated" | "held";

export interface BufferedPoseSample {
  mode: BufferedSampleMode;
  pose: SpatialPose;
  velocity: PoseVelocity;
  timestampMs: RealtimeTimestamp;
  sourceSequence: RealtimeSequence;
}
