import type { MnoteRuntimeConfig } from "@/lib/runtime-config";
import {
  buildDocumentBridgeContextWithActor,
  type BridgeContext,
  type BridgeTarget,
} from "@/lib/documents/bridge";
import { executeRustBridgeTool } from "@/lib/documents/rust-runtime";

type OnlyOfficeHeader = {
  name: string;
  value: string;
};

type OnlyOfficeServiceActorInput = {
  actorId?: string;
  actorType?: string;
  sessionId?: string | null;
  workspaceId?: string | null;
  sourceChannel: string;
  sourceClient: string;
  idempotencyKey?: string | null;
};

export type OnlyOfficeSignResult = {
  token: string | null;
  documentToken: string | null;
  editorConfigToken: string | null;
};

export type OnlyOfficeProxyPreparationResult = {
  targetUrl: string;
  forwardHeaders: OnlyOfficeHeader[];
};

export type OnlyOfficeCallbackPreparationResult = {
  shouldWrite: boolean;
  downloadUrl: string | null;
  idempotencyKey: string | null;
  locator: {
    assetId: string;
    workspaceId: string | null;
    documentId: string | null;
  };
  session: {
    sessionId: string;
    assetId: string;
    workspaceId: string | null;
    documentId: string | null;
    userId: string | null;
  };
};

export type OnlyOfficeForcesavePreparationResult = {
  requests: Array<{
    via: string;
    url: string;
    method: string;
    headers: OnlyOfficeHeader[];
    bodyJson: string;
  }>;
};

function buildOnlyOfficeServiceContext(request: Request, input: OnlyOfficeServiceActorInput): BridgeContext {
  return buildDocumentBridgeContextWithActor({
    request,
    workspaceId: input.workspaceId ?? null,
    actor: {
      actorType: input.actorType ?? "service",
      actorId: input.actorId?.trim() || "onlyoffice-service",
      sessionId: input.sessionId ?? null,
    },
    source: {
      channel: input.sourceChannel,
      client: input.sourceClient,
    },
    idempotencyKey: input.idempotencyKey ?? null,
  });
}

async function runOnlyOfficeTool<TResult>(input: {
  request: Request;
  toolName:
    | "onlyoffice_session_resolve"
    | "onlyoffice_sign"
    | "onlyoffice_prepare_proxy"
    | "onlyoffice_prepare_callback"
    | "onlyoffice_prepare_forcesave";
  args?: Record<string, unknown>;
  data?: Record<string, unknown>;
  target?: BridgeTarget | null;
  actor?: Partial<OnlyOfficeServiceActorInput>;
}): Promise<TResult> {
  const context = buildOnlyOfficeServiceContext(input.request, {
    actorId: input.actor?.actorId,
    actorType: input.actor?.actorType,
    sessionId: input.actor?.sessionId ?? null,
    workspaceId: input.actor?.workspaceId ?? null,
    sourceChannel: input.actor?.sourceChannel?.trim() || `onlyoffice:${input.toolName}`,
    sourceClient: input.actor?.sourceClient?.trim() || "wolai-frontend",
    idempotencyKey: input.actor?.idempotencyKey ?? null,
  });
  const result = await executeRustBridgeTool<TResult>({
    context,
    toolName: input.toolName,
    invocationKind: "job",
    args: input.args ?? {},
    data: input.data ?? {},
    target: input.target ?? null,
    mode: "result",
  });
  return result.result;
}

export async function signOnlyOfficeConfig(input: {
  request: Request;
  config: Record<string, unknown>;
  secret?: string | null;
}): Promise<OnlyOfficeSignResult> {
  return await runOnlyOfficeTool<OnlyOfficeSignResult>({
    request: input.request,
    toolName: "onlyoffice_sign",
    data: {
      config: input.config,
      secret: input.secret ?? "",
    },
    actor: {
      sourceChannel: "onlyoffice-sign",
      sourceClient: "onlyoffice-sign-route",
    },
  });
}

export async function prepareOnlyOfficeProxyRequest(input: {
  request: Request;
  encodedUrl: string;
  method: "GET" | "HEAD";
  range: string | null;
  runtimeConfig: MnoteRuntimeConfig;
}): Promise<OnlyOfficeProxyPreparationResult> {
  return await runOnlyOfficeTool<OnlyOfficeProxyPreparationResult>({
    request: input.request,
    toolName: "onlyoffice_prepare_proxy",
    data: {
      encodedUrl: input.encodedUrl,
      method: input.method,
      range: input.range,
      supabaseUrl: input.runtimeConfig.supabaseUrl ?? "",
      supabaseInternalUrl:
        input.runtimeConfig.supabaseInternalUrl ?? process.env.SUPABASE_INTERNAL_URL ?? "",
      onlyofficeStorageHostOverride: input.runtimeConfig.onlyofficeStorageHostOverride ?? "",
      convexOrigin:
        process.env.CONVEX_SELF_HOSTED_URL ?? process.env.NEXT_PUBLIC_CONVEX_URL ?? "",
      supabaseAnonKey: input.runtimeConfig.supabaseAnonKey ?? "",
    },
    actor: {
      sourceChannel: "onlyoffice-proxy",
      sourceClient: "onlyoffice-proxy-route",
    },
  });
}

export async function prepareOnlyOfficeCallback(input: {
  request: Request;
  assetId: string;
  documentId?: string | null;
  workspaceId?: string | null;
  userId?: string | null;
  sessionId?: string | null;
  status: number;
  url?: string | null;
  key?: string | null;
  onlyofficeInternalUrl: string;
}): Promise<OnlyOfficeCallbackPreparationResult> {
  return await runOnlyOfficeTool<OnlyOfficeCallbackPreparationResult>({
    request: input.request,
    toolName: "onlyoffice_prepare_callback",
    data: {
      assetId: input.assetId,
      documentId: input.documentId ?? null,
      workspaceId: input.workspaceId ?? null,
      userId: input.userId ?? null,
      sessionId: input.sessionId ?? "onlyoffice-callback",
      status: input.status,
      url: input.url ?? null,
      key: input.key ?? null,
      onlyofficeInternalUrl: input.onlyofficeInternalUrl,
    },
    actor: {
      actorId: input.userId?.trim() || "onlyoffice-callback",
      sessionId: "onlyoffice-callback",
      workspaceId: input.workspaceId ?? null,
      idempotencyKey: input.key ?? null,
      sourceChannel: "onlyoffice-callback",
      sourceClient: "onlyoffice-document-server",
    },
    target: {
      workspaceId: input.workspaceId ?? null,
      pageId: input.documentId ?? null,
      blockId: input.assetId,
    },
  });
}

export async function prepareOnlyOfficeForcesave(input: {
  request: Request;
  assetId: string;
  key: string;
  onlyofficeInternalUrl: string;
  secret?: string | null;
  actorId?: string;
  workspaceId?: string | null;
  documentId?: string | null;
}): Promise<OnlyOfficeForcesavePreparationResult> {
  return await runOnlyOfficeTool<OnlyOfficeForcesavePreparationResult>({
    request: input.request,
    toolName: "onlyoffice_prepare_forcesave",
    data: {
      assetId: input.assetId,
      key: input.key,
      onlyofficeInternalUrl: input.onlyofficeInternalUrl,
      secret: input.secret ?? "",
    },
    actor: {
      actorId: input.actorId?.trim() || "onlyoffice-forcesave",
      sessionId: "onlyoffice-forcesave",
      workspaceId: input.workspaceId ?? null,
      idempotencyKey: input.key,
      sourceChannel: "onlyoffice-forcesave",
      sourceClient: "onlyoffice-forcesave-route",
    },
    target: {
      workspaceId: input.workspaceId ?? null,
      pageId: input.documentId ?? null,
      blockId: input.assetId,
    },
  });
}
