import {
  deleteSavedSetupAckSchema,
  listSavedSetupsAckSchema,
  saveSetupAckSchema,
  updateSavedSetupAckSchema,
  WebappBoundPayloadOf,
  wrapInEnvelope,
} from "@mcpx/webapp-protocol/messages";
import { Logger } from "winston";
import { z } from "zod/v4";

export interface HubSocketAdapter {
  emitWithAck(event: string, envelope: unknown): Promise<unknown>;
}

export class SavedSetupsClient {
  private logger: Logger;

  constructor(
    private getSocket: () => HubSocketAdapter | null,
    logger: Logger,
  ) {
    this.logger = logger.child({ component: "SavedSetupsClient" });
  }

  async saveSetup(
    payload: WebappBoundPayloadOf<"save-setup">,
  ): Promise<z.infer<typeof saveSetupAckSchema>> {
    const socket = this.getSocket();
    if (!socket) {
      return { success: false, error: "Not connected to Hub" };
    }
    const envelope = wrapInEnvelope({ payload });
    this.logger.debug("Sending save-setup to Hub", {
      messageId: envelope.metadata.id,
    });
    const ack = await socket.emitWithAck("save-setup", envelope);
    const parsed = saveSetupAckSchema.safeParse(ack);
    if (!parsed.success) {
      this.logger.error("Invalid save-setup ack from Hub", {
        error: parsed.error,
        ack,
      });
      return { success: false, error: "Invalid response from Hub" };
    }
    return parsed.data;
  }

  async listSavedSetups(): Promise<z.infer<typeof listSavedSetupsAckSchema>> {
    const socket = this.getSocket();
    if (!socket) {
      return { setups: [] };
    }
    const envelope = wrapInEnvelope({ payload: {} });
    this.logger.debug("Sending list-saved-setups to Hub");
    const ack = await socket.emitWithAck("list-saved-setups", envelope);
    const parsed = listSavedSetupsAckSchema.safeParse(ack);
    if (!parsed.success) {
      this.logger.error("Invalid list-saved-setups ack from Hub", {
        error: parsed.error,
        ack,
      });
      return { setups: [] };
    }
    return parsed.data;
  }

  async deleteSavedSetup(
    savedSetupId: string,
  ): Promise<z.infer<typeof deleteSavedSetupAckSchema>> {
    const socket = this.getSocket();
    if (!socket) {
      return { success: false, error: "Not connected to Hub" };
    }
    const envelope = wrapInEnvelope({ payload: { savedSetupId } });
    this.logger.debug("Sending delete-saved-setup to Hub", { savedSetupId });
    const ack = await socket.emitWithAck("delete-saved-setup", envelope);
    const parsed = deleteSavedSetupAckSchema.safeParse(ack);
    if (!parsed.success) {
      this.logger.error("Invalid delete-saved-setup ack from Hub", {
        error: parsed.error,
        ack,
      });
      return { success: false, error: "Invalid response from Hub" };
    }
    return parsed.data;
  }

  async updateSavedSetup(
    payload: WebappBoundPayloadOf<"update-saved-setup">,
  ): Promise<z.infer<typeof updateSavedSetupAckSchema>> {
    const socket = this.getSocket();
    if (!socket) {
      return { success: false, error: "Not connected to Hub" };
    }
    const envelope = wrapInEnvelope({ payload });
    this.logger.debug("Sending update-saved-setup to Hub", {
      savedSetupId: payload.savedSetupId,
    });
    const ack = await socket.emitWithAck("update-saved-setup", envelope);
    const parsed = updateSavedSetupAckSchema.safeParse(ack);
    if (!parsed.success) {
      this.logger.error("Invalid update-saved-setup ack from Hub", {
        error: parsed.error,
        ack,
      });
      return { success: false, error: "Invalid response from Hub" };
    }
    return parsed.data;
  }
}
