export type DbosNativeStatus =
  | "ENQUEUED"
  | "DELAYED"
  | "PENDING"
  | "SUCCESS"
  | "ERROR"
  | "CANCELLED"
  | "MAX_RECOVERY_ATTEMPTS_EXCEEDED";

export interface DbosWorkflowRecord {
  readonly workflowId: string;
  readonly workflowKind: string;
  readonly status: DbosNativeStatus;
  readonly createdAt?: string;
  readonly updatedAt?: string;
  readonly output?: unknown;
  readonly error?: unknown;
}

export interface DbosStartRequest {
  readonly workflowId: string;
  readonly workflowKind: string;
  readonly input: unknown;
  readonly idempotencyKey: string;
  readonly correlationId: string;
  readonly operationId: string;
}

export interface DbosRuntime {
  start(request: DbosStartRequest): Promise<DbosWorkflowRecord>;
  get(workflowId: string): Promise<DbosWorkflowRecord | undefined>;
  cancel(workflowId: string): Promise<void>;
}

export type RegisteredDbosWorkflow = (input: unknown) => Promise<unknown>;

export interface DbosWorkflowRegistry {
  resolve(workflowKind: string): RegisteredDbosWorkflow | undefined;
}

interface DbosSdkWorkflowHandle {
  workflowID(): string;
  getStatus(): Promise<DbosSdkWorkflowStatus | null>;
}

interface DbosSdkWorkflowStatus {
  workflowID?: string;
  workflowUUID?: string;
  workflowName?: string;
  status: DbosNativeStatus;
  createdAt?: string;
  updatedAt?: string;
  output?: unknown;
  error?: unknown;
}

export interface DbosSdkSurface {
  startWorkflow(
    target: RegisteredDbosWorkflow,
    params: {
      workflowID: string;
      workflowAttributes: Readonly<Record<string, unknown>>;
    },
  ): (input: unknown) => Promise<DbosSdkWorkflowHandle>;
  getWorkflowStatus(workflowId: string): Promise<DbosSdkWorkflowStatus | null>;
  cancelWorkflow(workflowId: string, options?: { cancelChildren?: boolean }): Promise<void>;
}

/**
 * Structural bridge for @dbos-inc/dbos-sdk 4.25.x.
 *
 * Keeping the SDK surface structural lets this provider remain the only place that
 * understands DBOS mechanics while preventing SDK classes from entering AWP ports.
 */
export class DbosSdkRuntime implements DbosRuntime {
  constructor(
    private readonly dbos: DbosSdkSurface,
    private readonly registry: DbosWorkflowRegistry,
  ) {}

  async start(request: DbosStartRequest): Promise<DbosWorkflowRecord> {
    const target = this.registry.resolve(request.workflowKind);
    if (!target) {
      throw new Error(`Unsupported DBOS workflow kind: ${request.workflowKind}`);
    }

    const handle = await this.dbos.startWorkflow(target, {
      workflowID: request.workflowId,
      workflowAttributes: {
        awpOperationId: request.operationId,
        awpCorrelationId: request.correlationId,
        awpIdempotencyKey: request.idempotencyKey,
        awpWorkflowKind: request.workflowKind,
      },
    })(request.input);

    const status = await handle.getStatus();
    if (!status) {
      return {
        workflowId: handle.workflowID(),
        workflowKind: request.workflowKind,
        status: "PENDING",
      };
    }
    return mapSdkStatus(status, request.workflowKind, handle.workflowID());
  }

  async get(workflowId: string): Promise<DbosWorkflowRecord | undefined> {
    const status = await this.dbos.getWorkflowStatus(workflowId);
    if (!status) return undefined;
    return mapSdkStatus(status, status.workflowName ?? "unknown", workflowId);
  }

  async cancel(workflowId: string): Promise<void> {
    await this.dbos.cancelWorkflow(workflowId, { cancelChildren: true });
  }
}

function mapSdkStatus(
  status: DbosSdkWorkflowStatus,
  workflowKind: string,
  fallbackId: string,
): DbosWorkflowRecord {
  return {
    workflowId: status.workflowID ?? status.workflowUUID ?? fallbackId,
    workflowKind,
    status: status.status,
    ...(status.createdAt === undefined ? {} : { createdAt: status.createdAt }),
    ...(status.updatedAt === undefined ? {} : { updatedAt: status.updatedAt }),
    ...(status.output === undefined ? {} : { output: status.output }),
    ...(status.error === undefined ? {} : { error: status.error }),
  };
}
