import { Session } from "@shopify/shopify-api";
import { registerShop, getShopWithDecryptedToken } from "../../services/shop.server";
import prisma from "../../db.server";
import { logger } from "../security/logger";

/**
 * Custom Multi-Tenant Session Storage for Shopify OAuth.
 * Automatically encrypts access tokens and binds sessions to Shop records.
 */
export class EncryptedMultiTenantSessionStorage {
  async storeSession(session: Session): Promise<boolean> {
    try {
      const shopDomain = session.shop.toLowerCase().trim();
      const accessToken = session.accessToken || "";

      if (accessToken) {
        await registerShop({
          shopifyDomain: shopDomain,
          accessToken,
          scopes: session.scope || process.env.SCOPES || "read_products,read_content",
          tokenExpiresAt: session.expires,
        });
      }

      logger.info(`Session stored for merchant: ${shopDomain}`, {
        shop: shopDomain,
        isOnline: session.isOnline,
        expires: session.expires,
      });

      return true;
    } catch (error) {
      logger.error("Failed to store encrypted multi-tenant session", error, { shop: session.shop });
      return false;
    }
  }

  async loadSession(id: string): Promise<Session | undefined> {
    try {
      // If id is a shop domain or session key
      const shopDomain = id.includes(".myshopify.com") ? id : id.split("_")[0];
      const shop = await getShopWithDecryptedToken(shopDomain);

      if (!shop || shop.uninstalledAt || !shop.decryptedAccessToken) {
        return undefined;
      }

      const session = new Session({
        id,
        shop: shop.shopifyDomain,
        state: "active",
        isOnline: false,
        scope: shop.scopes,
        accessToken: shop.decryptedAccessToken,
        expires: shop.tokenExpiresAt || undefined,
      });

      return session;
    } catch (error) {
      logger.error("Failed to load session", error, { id });
      return undefined;
    }
  }

  async deleteSession(id: string): Promise<boolean> {
    try {
      const shopDomain = id.includes(".myshopify.com") ? id : id.split("_")[0];
      await prisma.shop.updateMany({
        where: { shopifyDomain: shopDomain },
        data: { uninstalledAt: new Date() },
      });
      return true;
    } catch (error) {
      logger.error("Failed to delete session", error, { id });
      return false;
    }
  }

  async deleteSessions(ids: string[]): Promise<boolean> {
    for (const id of ids) {
      await this.deleteSession(id);
    }
    return true;
  }

  async findSessionsByShop(shop: string): Promise<Session[]> {
    const session = await this.loadSession(shop);
    return session ? [session] : [];
  }
}
