import { LoginStatus } from "@/data/dto/auth";
import { AuthStorage, type IAuthStorage } from "@/data/storage/auth";
import { UserStorage, type IUserStorage } from "@/data/storage/user";
import { Result, type Result as ResultT } from "@/utils/result";

export type ChatCacheIdentityResolver = () => Promise<ResultT<string>>;

type ChatCacheAuthStorage = Pick<
  IAuthStorage,
  "getLoginProvider" | "getDeviceId"
>;
type ChatCacheUserStorage = Pick<IUserStorage, "getUserId">;

/**
 * Resolve the only identity allowed to access the current chat cache.
 *
 * A user id is shared by neither account switches nor guest/account changes,
 * so it is the preferred namespace for both authenticated and guest users.
 * The device id is only a safe fallback for an active guest session. Real
 * accounts without a persisted user id must skip the cache instead of falling
 * back to a device-wide or anonymous namespace.
 */
export async function resolveChatCacheOwnerKey(
  authStorage: ChatCacheAuthStorage = AuthStorage.getInstance(),
  userStorage: ChatCacheUserStorage = UserStorage.getInstance(),
): Promise<ResultT<string>> {
  const providerResult = await authStorage.getLoginProvider();
  if (Result.isErr(providerResult)) return providerResult;
  if (
    providerResult.data === null ||
    providerResult.data === LoginStatus.NotLoggedIn
  ) {
    return Result.err(new Error("Chat cache identity is unavailable."));
  }

  const userIdResult = await userStorage.getUserId();
  if (Result.isErr(userIdResult)) return userIdResult;
  if (userIdResult.data && userIdResult.data.length > 0) {
    return Result.ok(`user:${userIdResult.data}`);
  }

  if (providerResult.data === LoginStatus.Guest) {
    const deviceIdResult = await authStorage.getDeviceId();
    if (Result.isErr(deviceIdResult)) return deviceIdResult;
    if (deviceIdResult.data && deviceIdResult.data.length > 0) {
      return Result.ok(`device:${deviceIdResult.data}`);
    }
  }

  return Result.err(new Error("Chat cache identity is unavailable."));
}
