import log4js from "log4js";
import { BrowserView } from "electrobun/bun";
import { startWaiting, stopWaiting } from "../spinner.js";
import { setMessageSender, sendIPC } from "./notify.js";

const logger = log4js.getLogger("RPC");
let mainWindow = null;

export function createAppRpc() {
  return BrowserView.defineRPC({
    maxRequestTime: 30000,
    handlers: {
      requests: {
        getData: async () => {
          startWaiting("Getting data...", logger);
          try {
            const socketClient = global.socketClient;

            if (!socketClient) {
              pushState({
                authenticated: false,
                connected: false,
                loading: false,
                host: {},
                printers: [],
                documentPrinters: [],
              });
              await stopWaiting();
              return { ok: true };
            }

            pushState({
              authenticated: socketClient.authenticated,
              connected: socketClient.connected,
              loading: socketClient.loading,
              host: socketClient.host || {},
              printers: socketClient.printerManager.printers || [],
              documentPrinters:
                socketClient.documentPrinterManager.documentPrinters || [],
            });
            await stopWaiting();
            return { ok: true };
          } catch (error) {
            logger.error("Error getting printer data:", error);
            pushState({
              authenticated: false,
              connected: false,
              loading: false,
              host: {},
              printers: [],
              documentPrinters: [],
            });
            await stopWaiting();
            return { ok: false };
          }
        },
        authenticateOTP: async ({ otp }) => {
          startWaiting("Authenticating with OTP...", logger);
          try {
            const socketClient = global.socketClient;
            if (socketClient) {
              await socketClient.authenticateWithOtp(otp);
            } else {
              logger.error("Socket client not available for OTP authentication");
            }
            await stopWaiting();
            return { ok: true };
          } catch (error) {
            await stopWaiting();
            logger.error("Error during OTP authentication:", error);
            return { ok: false };
          }
        },
        minimizeWindow: async () => {
          if (mainWindow && !mainWindow.isDestroyed?.()) {
            mainWindow.minimize();
          }
          return { ok: true };
        },
        maximizeWindow: async () => {
          if (mainWindow && !mainWindow.isDestroyed?.()) {
            if (mainWindow.isMaximized?.()) {
              mainWindow.unmaximize();
            } else {
              mainWindow.maximize();
            }
          }
          return { ok: true };
        },
        closeWindow: async () => {
          if (mainWindow && !mainWindow.isDestroyed?.()) {
            mainWindow.close();
          }
          return { ok: true };
        },
      },
      messages: {},
    },
  });
}

function pushState({
  authenticated,
  connected,
  loading,
  host,
  printers,
  documentPrinters,
}) {
  sendIPC("setAuthenticated", authenticated);
  sendIPC("setConnected", connected);
  sendIPC("setLoading", loading);
  sendIPC("setHost", host);
  sendIPC("setPrinters", printers);
  sendIPC("setDocumentPrinters", documentPrinters);
}

export function registerMainWindow(window) {
  mainWindow = window;
  global.mainWindow = window;
}

export async function setupIPC(window = mainWindow) {
  if (window) {
    registerMainWindow(window);
  }

  if (!mainWindow) {
    logger.warn("No main window available, skipping RPC setup");
    return;
  }

  setMessageSender((channel, data) => {
    try {
      const send = mainWindow?.webview?.rpc?.send;

      if (send) {
        send[channel](data);
        logger.info(`Message sent to main window on channel: ${channel}`, data);
        return;
      }

      logger.warn(
        `No RPC sender available for channel: ${channel}. Is the window ready?`,
      );
    } catch (error) {
      logger.error(`Error sending message on channel ${channel}:`, error);
    }
  });

  logger.info("RPC handlers ready");
}
