import PouchDB from "./PouchDB";
import type {
  MessageDocument,
  QRCodeDocument,
  ServerSettingsDocument,
  UserChatSettingsDocument,
  WebPushSubscriptionDocument,
} from "@hereconnect/types";
import { PushSubscription } from "web-push";

export interface ServiceSeqTrackerDocument {
  lastSeq: string | number;
}

if (!process.env.API_URL) {
  throw new Error("Environment variable API_URL is not set");
}

export const messagesDbUrl = `${process.env.API_URL}/messages`;

export const serverSettingsDb = new PouchDB<ServerSettingsDocument>(
  `${process.env.API_URL}/server_settings`,
  {
    skip_setup: true,
  },
);
export const qrDb = new PouchDB<QRCodeDocument>(`${process.env.API_URL}/qr`, {
  skip_setup: true,
});

export const webPushSubscriptionsDb = new PouchDB<
  WebPushSubscriptionDocument<PushSubscription>
>(`${process.env.API_URL}/web_push_subscriptions`, {
  skip_setup: true,
});

export const { messagesDb, serviceSeqTrackerDb } = (() => {
  const messagesDB = new PouchDB(messagesDbUrl, {
    skip_setup: true,
  });

  return {
    messagesDb: messagesDB as PouchDB.Database<MessageDocument>,
    serviceSeqTrackerDb:
      messagesDB as PouchDB.Database<ServiceSeqTrackerDocument>,
  } as const;
})();

export const userChatSettingsDb = new PouchDB<UserChatSettingsDocument>(
  `${process.env.API_URL}/user_chat_settings`,
  {
    skip_setup: true,
  },
);

export const checkDatabases = async () => {
  const entries = await Promise.all(
    Object.entries({
      serverSettingsDb,
      qrDb,
      webPushSubscriptionsDb,
      messagesDb,
      userChatSettingsDb,
    } as const).map(
      async ([name, db]): Promise<
        [string, Awaited<ReturnType<typeof db.info>>]
      > => {
        const info = await db.info();
        return [name, info];
      },
    ),
  );

  for (const [name, info] of entries) {
    if ("error" in info && "reason" in info) {
      throw new Error(`[${name}] ${info.error}: ${info.reason}`);
    }
    if ("error" in info) {
      throw new Error(`[${name}] ${info.error}`);
    }
  }

  return Object.fromEntries(entries);
};
