import type { ServerWebSocket } from "bun";
import type { CoreDispatchMessage, JsonValue } from "../../shared/src/index";
import type { Socket } from "node:net";
import type postgres from "postgres";

export interface RuntimeConfig {
  port: number;
  providerPort: number;
  databaseUrl: string;
  identity: RuntimeIdentity;
  providerToken: string;
  heartbeatTimeoutMs: number;
  taskPendingTimeoutMs: number;
  databaseVolumeName: string;
  databaseVolumeSize: string;
  pgdataBackupStagingDir: string;
  baiduNetdiskInternalUrl: string;
  microservices: MicroserviceConfig[];
  logFile: string;
  databasePoolMax: number;
}

export interface RuntimeIdentity {
  environment: string;
  namespace: string;
  databaseName: string;
  deployRef: string;
  serviceId: string;
  repo: string;
  commit: string;
  requestedCommit: string;
}

export interface MicroserviceConfig {
  id: string;
  name: string;
  providerId: string;
  description: string;
  repository: {
    url: string;
    commitId: string;
    dockerfile: string;
    artifactSource?: {
      kind: "upstream-image";
      imageRef: string;
      digestPinRequired: boolean;
      mirrorRepository: string;
      ciDockerfileBuild: boolean;
      pullOnlyCd: boolean;
    };
    composeFile: string;
    composeService: string;
    containerName: string;
  };
  backend: {
    nodeBaseUrl: string;
    nodeBindHost: string;
    nodePort: number;
    proxyMode: string;
    frontendOnly: boolean;
    public: boolean;
    allowedMethods: string[];
    allowedPathPrefixes: string[];
    healthPath: string;
    timeoutMs: number;
  };
  deployment: {
    mode: "unidesk-direct" | "k3sctl-managed" | "internal-sidecar";
    adapterServiceId?: string;
    k3sServiceId?: string;
    namespace?: string;
    expectedNodeIds?: string[];
    activeNodeId?: string;
  };
  development: {
    providerId: string;
    sshPassthrough: boolean;
    worktreePath: string;
  };
  frontend: {
    route: string;
    integrated: boolean;
  };
}

export interface WsData {
  providerId?: string;
  channel?: "provider" | "ssh";
  sessionId?: string;
}

export type ProviderSocket = ServerWebSocket<WsData>;

export type SqlClient = ReturnType<typeof postgres>;

export interface RequestPerformanceSample {
  at: string;
  component: string;
  method: string;
  path: string;
  status: number;
  durationMs: number;
  ok: boolean;
}

export interface OperationPerformanceSample {
  at: string;
  service: string;
  operation: string;
  durationMs: number;
  ok: boolean;
  detail: string;
}

export interface RawTaskRow {
  id: string;
  provider_id: string;
  command: string;
  status: string;
  payload: JsonValue;
  result: JsonValue | null;
  updated_at: Date | string;
}

export interface ScheduledTaskRow {
  id: string;
  name: string;
  description: string;
  enabled: boolean;
  schedule_json: JsonValue;
  action_json: JsonValue;
  concurrency_policy: string;
  next_run_at: Date | string | null;
  last_run_at: Date | string | null;
  last_run_id: string | null;
  created_at: Date | string;
  updated_at: Date | string;
}

export interface ScheduledTaskRunRow {
  id: string;
  schedule_id: string;
  trigger_type: string;
  status: string;
  task_id: string | null;
  result: JsonValue | null;
  error: string | null;
  started_at: Date | string | null;
  finished_at: Date | string | null;
  duration_ms: number | string | null;
  created_at: Date | string;
  updated_at: Date | string;
}

export interface ScheduleSpec {
  type: "daily" | "interval";
  timeOfDay?: string;
  timezone?: string;
  everySeconds?: number;
}

export interface DispatchScheduleAction {
  type: "dispatch";
  providerId: string;
  command: CoreDispatchMessage["command"];
  payload: Record<string, JsonValue>;
  timeoutMs?: number;
}

export interface PgdataBackupScheduleAction {
  type: "pgdata_backup";
  volumeName: string;
  remoteBaseDir: string;
  stagingSubdir: string;
  baiduBaseUrl: string;
  timeoutMs: number;
  cleanupLocal: boolean;
}

export type ScheduleAction = DispatchScheduleAction | PgdataBackupScheduleAction;

export type TaskTerminalWaiter = (task: RawTaskRow | null) => void;

export interface EgressTcpConnection {
  providerId: string;
  connectionId: string;
  socket: Socket;
  provider: ProviderSocket;
  connectTimer: ReturnType<typeof setTimeout> | null;
  idleTimer: ReturnType<typeof setTimeout> | null;
}

export type HttpTunnelFailureReason =
  | "timeout"
  | "aborted"
  | "provider-disconnected"
  | "provider-mismatch"
  | "send-failed";

export interface MicroserviceProxyCacheEntry {
  expiresAt: number;
  staleExpiresAt: number;
  status: number;
  contentType: string;
  bodyText: string;
}

export interface MicroserviceHealthAssessment {
  healthy: boolean;
  reason: string;
  checks: Record<string, JsonValue>;
  body: JsonValue;
}

export interface MicroserviceAvailabilityEntry {
  expiresAt: number;
  probe: Record<string, JsonValue>;
}

export type HttpTunnelWaiter = (message: {
  providerId: string;
  requestId: string;
  ok: boolean;
  result: JsonValue;
} | null, reason?: HttpTunnelFailureReason) => void;

export type LoggerFn = (level: "debug" | "info" | "warn" | "error", message: string, data?: JsonValue) => void;
