import { api } from "@/lib/convex/api";
import { getAuthedConvexClient } from "@/lib/convex/route";
import {
  buildDocumentBridgeMutationRequest,
  executeDocumentBridgeMutationRequest,
  type BridgeContext,
  type CommandEnvelope,
  DocumentBridgeError,
} from "@/lib/documents/bridge";
import {
  recordBridgeCommandArtifacts,
  recordBridgeCommandFailureArtifacts,
} from "@/lib/documents/bridge-log";
import type { DocumentOptionsUpdatePayload, DocumentTitleUpdatePayload } from "@/lib/documents/metadata-command-adapter";
import type { DocumentSavePayload } from "@/lib/documents/save-contract";
import {
  executeRustBridgeMutationTransport,
  resolveRustBridgeCommandPlan,
} from "@/lib/documents/rust-runtime";

type PageWritePayload =
  | DocumentTitleUpdatePayload
  | DocumentOptionsUpdatePayload
  | DocumentSavePayload;

type MetadataMutationArgs = Record<string, unknown>;

type PageWriteAdapter<TPayload> = {
  kind: "rust_transport" | "convex_mutation";
  convexMutation?: unknown;
  mapConvexArgs?: (payload: TPayload) => MetadataMutationArgs;
};

export type PageWriteCommandExecutionResult = {
  requestId: string;
  traceId: string;
  commandId: string;
  commandName: string;
  revision: number | null;
  conflictDetectionKey: string | null;
};

function mapDocumentOptionsToConvexArgs(payload: DocumentOptionsUpdatePayload) {
  return {
    id: payload.documentId,
    options: {
      wideLayout: payload.options.wideLayout,
      smallText: payload.options.smallText,
      showHeadingNumbers: payload.options.showHeadingNumbers,
      showToc: payload.options.showToc,
      showStructure: payload.options.showStructure,
      protectEditing: payload.options.protectEditing,
      showWordCount: payload.options.showWordCount,
      collapseBacklinks: payload.options.collapseBacklinks,
      pageFont: payload.options.pageFont,
      layoutDensity: payload.options.layoutDensity,
      hideChildPages: payload.options.hideChildPages,
      showBlockRefCount: payload.options.showBlockRefCount,
      embedDefaultBlockId:
        typeof payload.options.embedDefaultBlockId === "string" ? payload.options.embedDefaultBlockId : null,
    },
  };
}

const pageWriteAdapters: Record<string, PageWriteAdapter<unknown>> = {
  "page.head.updateTitle": {
    kind: "rust_transport",
  },
  "page.layout.updateOptions": {
    kind: "convex_mutation",
    convexMutation: api.documents.updateOptions,
    mapConvexArgs: mapDocumentOptionsToConvexArgs,
  },
  "page.body.save": {
    kind: "rust_transport",
  },
};

function getPageWriteAdapter<TPayload>(commandName: string): PageWriteAdapter<TPayload> {
  const adapter = pageWriteAdapters[commandName];
  if (!adapter) {
    throw new Error(`未注册页面写命令适配器: ${commandName}`);
  }
  return adapter as PageWriteAdapter<TPayload>;
}

function normalizePersistedMeta(result: unknown): Pick<PageWriteCommandExecutionResult, "revision" | "conflictDetectionKey"> {
  const record = result && typeof result === "object" ? (result as Record<string, unknown>) : null;
  return {
    revision:
      typeof record?.revision === "number" && Number.isInteger(record.revision)
        ? record.revision
        : null,
    conflictDetectionKey:
      typeof record?.conflict_detection_key === "string" && record.conflict_detection_key.trim()
        ? record.conflict_detection_key.trim()
        : null,
  };
}

export async function executePageWriteBridgeCommand<TPayload extends PageWritePayload>(input: {
  context: BridgeContext;
  envelope: CommandEnvelope<TPayload>;
}): Promise<PageWriteCommandExecutionResult> {
  const { client } = await getAuthedConvexClient();
  const adapter = getPageWriteAdapter<TPayload>(input.envelope.name);

  try {
    if (adapter.kind === "rust_transport") {
      const plan = await resolveRustBridgeCommandPlan({
        context: input.context,
        envelope: input.envelope,
      });
      const transportResult = await executeRustBridgeMutationTransport({
        client,
        plan,
      });
      const persistedMeta = normalizePersistedMeta(transportResult);

      await recordBridgeCommandArtifacts({
        context: input.context,
        envelope: input.envelope,
      });

      return {
        requestId: input.context.requestId,
        traceId: input.context.traceId,
        commandId: input.envelope.commandId,
        commandName: input.envelope.name,
        revision: persistedMeta.revision,
        conflictDetectionKey: persistedMeta.conflictDetectionKey,
      };
    }

    const mutationRequest = buildDocumentBridgeMutationRequest({
      context: input.context,
      envelope: input.envelope,
      mapConvexArgs: adapter.mapConvexArgs!,
    });

    await executeDocumentBridgeMutationRequest({
      client,
      mutation: adapter.convexMutation!,
      request: mutationRequest,
    });

    await recordBridgeCommandArtifacts({
      context: input.context,
      envelope: input.envelope,
    });

    return {
      requestId: input.context.requestId,
      traceId: input.context.traceId,
      commandId: input.envelope.commandId,
      commandName: input.envelope.name,
      revision: null,
      conflictDetectionKey: null,
    };
  } catch (error) {
    await recordBridgeCommandFailureArtifacts({
      context: input.context,
      envelope: input.envelope,
      client,
      error,
    });
    if (
      input.envelope.name === "page.body.save" &&
      error instanceof Error &&
      /正文(内容已变更|冲突检测失败)/.test(error.message)
    ) {
      throw new DocumentBridgeError(error.message, 409, "REJECTED", {
        reason: "content_conflict",
        revision: (input.envelope.payload as DocumentSavePayload).revision,
        conflictDetectionKey: (input.envelope.payload as DocumentSavePayload).conflictDetectionKey,
      });
    }
    throw error;
  }
}
