import "server-only";
import { Client } from "@atproto/lex";
import { IdResolver } from "@atproto/identity";
import { TokenRefreshError } from "@atproto/oauth-client";
import { refresh } from "next/cache";
import { getSession } from "@/auth/session";
import { getOAuthClient } from "@/auth/client";

const idResolver = new IdResolver();

export class AuthRequiredError extends Error {
  constructor(message = "Authentication required") {
    super(message);
    this.name = "AuthRequiredError";
  }
}

/**
 * Get an unauthenticated lex Client for reading from a user's PDS.
 * Resolves the DID to find the PDS endpoint, then creates a client that hits it directly.
 * Use this for read-only operations to avoid OAuth client's CachedGetter issues with "use cache".
 */
export async function getPublicLexClient(did: string): Promise<Client> {
  const atprotoData = await idResolver.did.resolveAtprotoData(did);
  const pdsUrl = atprotoData.pds;
  return new Client(pdsUrl);
}

/**
 * Get an authenticated lex Client for the current user.
 * Throws AuthRequiredError if not authenticated.
 * If the OAuth session is invalid/deleted, clears the cookie and throws AuthRequiredError.
 */
export async function getLexClient(): Promise<Client> {
  const session = await getSession();
  if (!session.did) {
    throw new AuthRequiredError();
  }

  const oauthClient = await getOAuthClient();

  let oauthSession;
  try {
    oauthSession = await oauthClient.restore(session.did);
  } catch (err) {
    if (err instanceof TokenRefreshError) {
      const cause = err.cause instanceof Error ? err.cause.message : err.cause;
      console.log(`[auth] TokenRefreshError ${session.did}: ${err.message} (cause: ${cause})`);
      session.destroy();
      refresh();
    } else {
      const msg = err instanceof Error ? err.message : err;
      console.log(`[auth] restore failed ${session.did}: ${msg}`);
    }
    throw err;
  }

  if (!oauthSession) {
    throw new AuthRequiredError();
  }

  // Create lex Client directly from OAuth session (idiomatic usage)
  return new Client(oauthSession);
}
