import { describe, expect, it, vi } from "vitest";

import {
  FacebookIdentityResponse,
  FacebookPsidLoginResponse,
  LoginStatus,
} from "@/data/dto/auth";
import { AuthRepository } from "@/data/repositories/auth_repository";
import type { AuthApi } from "@/data/services/api";
import type { IAuthStorage } from "@/data/storage/auth";
import type { IUserStorage } from "@/data/storage/user";
import { Result } from "@/utils/result";

function createRepository(overrides: Partial<AuthApi>) {
  const storage = {
    setAsid: vi.fn(async () => Result.ok(undefined)),
    setPsid: vi.fn(async () => Result.ok(undefined)),
    setLoginToken: vi.fn(async () => Result.ok(undefined)),
    setRefreshToken: vi.fn(async () => Result.ok(undefined)),
    setLoginProvider: vi.fn(async () => Result.ok(undefined)),
    setGuestToken: vi.fn(async () => Result.ok(undefined)),
    setDeviceId: vi.fn(async () => Result.ok(undefined)),
  } as unknown as IAuthStorage;
  const userStorage = {
    setUser: vi.fn(async () => Result.ok(undefined)),
    setUserId: vi.fn(async () => Result.ok(undefined)),
  } as unknown as IUserStorage;
  const repository = new AuthRepository(
    overrides as AuthApi,
    storage,
    userStorage,
  );
  return { repository, storage, userStorage };
}

describe("AuthRepository facebook identity", () => {
  it("binds facebook identity and stores returned ids", async () => {
    const bindFacebookIdentity = vi.fn(async () =>
      FacebookIdentityResponse.fromJson({
        fbAsid: "asid-1",
        fbPsid: "psid-1",
        facebookBinding: { conflicts: [], bound: [] },
      }),
    );
    const { repository, storage } = createRepository({ bindFacebookIdentity });

    const result = await repository.bindFacebookIdentity({
      asid: "asid-1",
      psid: "psid-1",
    });

    expect(result.success).toBe(true);
    expect(bindFacebookIdentity).toHaveBeenCalledOnce();
    expect(storage.setAsid).toHaveBeenCalledWith("asid-1");
    expect(storage.setPsid).toHaveBeenCalledWith("psid-1");
  });

  it("saves real login data from complete psid login responses", async () => {
    const facebookPsidLogin = vi.fn(async () =>
      FacebookPsidLoginResponse.fromJson({
        token: "login-token",
        refreshToken: "refresh-token",
        matchedBy: "psid",
        fbAsid: "asid-1",
        fbPsid: "psid-1",
        hasCompleteFacebookIdentity: true,
        isGuest: false,
        user: { id: "user-1", username: "Elio" },
      }),
    );
    const { repository, storage, userStorage } = createRepository({
      facebookPsidLogin,
    });

    const result = await repository.facebookPsidLogin({
      psid: "psid-1",
      deviceId: "device-1",
    });

    expect(result).toEqual(Result.ok(LoginStatus.Facebook));
    expect(storage.setLoginToken).toHaveBeenCalledWith("login-token");
    expect(storage.setRefreshToken).toHaveBeenCalledWith("refresh-token");
    expect(storage.setLoginProvider).toHaveBeenCalledWith(LoginStatus.Facebook);
    expect(userStorage.setUserId).toHaveBeenCalledWith("user-1");
    expect(storage.setAsid).toHaveBeenCalledWith("asid-1");
    expect(storage.setPsid).toHaveBeenCalledWith("psid-1");
  });

  it("saves guest data from incomplete psid login responses", async () => {
    const facebookPsidLogin = vi.fn(async () =>
      FacebookPsidLoginResponse.fromJson({
        token: "guest-token",
        matchedBy: "psid_incomplete",
        fbPsid: "psid-1",
        hasCompleteFacebookIdentity: false,
        isGuest: true,
        userId: "guest-1",
      }),
    );
    const { repository, storage, userStorage } = createRepository({
      facebookPsidLogin,
    });

    const result = await repository.facebookPsidLogin({
      psid: "psid-1",
      deviceId: "device-1",
    });

    expect(result).toEqual(Result.ok(LoginStatus.Guest));
    expect(storage.setGuestToken).toHaveBeenCalledWith("guest-token");
    expect(storage.setLoginProvider).toHaveBeenCalledWith(LoginStatus.Guest);
    expect(storage.setDeviceId).toHaveBeenCalledWith("device-1");
    expect(userStorage.setUserId).toHaveBeenCalledWith("guest-1");
  });
});
