import { IRepositoryManager } from "@/contexts/common/domain";
import { ISequelizeAdapter } from "@/contexts/common/infrastructure/sequelize";
import { UniqueID } from "@shared/contexts";
import { IQuoteRepository } from "../../domain";

import { Quote } from "../../domain/entities/Quotes/Quote";
import { ISalesContext } from "../../infrastructure";
import { GetQuoteUseCase } from "./GetQuote.useCase";

describe("GetQuoteUseCase", () => {
  let getQuoteUseCase: GetQuoteUseCase;
  let mockAdapter: jest.Mocked<ISequelizeAdapter>;
  let mockRepositoryManager: jest.Mocked<IRepositoryManager>;
  let mockQuoteRepository: jest.Mocked<IQuoteRepository>;
  let mockTransaction: { complete: jest.Mock };

  beforeEach(() => {
    mockTransaction = { complete: jest.fn() };

    mockAdapter = {
      startTransaction: jest.fn().mockReturnValue(mockTransaction),
    } as unknown as jest.Mocked<ISequelizeAdapter>;

    mockQuoteRepository = {
      getById: jest.fn(),
    } as unknown as jest.Mocked<IQuoteRepository>;

    mockRepositoryManager = {
      getRepository: jest.fn().mockReturnValue(() => mockQuoteRepository),
    } as unknown as jest.Mocked<IRepositoryManager>;

    const context: ISalesContext = {
      adapter: mockAdapter,
      repositoryManager: mockRepositoryManager,
      dealer: undefined,
    };

    getQuoteUseCase = new GetQuoteUseCase(context);
  });

  it("should return a quote when found", async () => {
    const id = new UniqueID();
    const quote = new Quote({ id, content: "Test Quote" });

    mockQuoteRepository.getById.mockResolvedValueOnce(quote);
    mockTransaction.complete.mockImplementationOnce(async (fn: any) => await fn({}));

    const request = { id };
    const response = await getQuoteUseCase.execute(request);

    expect(response.isSuccess).toBe(true);
    expect(response.getValue()).toEqual(quote);
  });

  it("should return a NOT_FOUND_ERROR when quote is not found", async () => {
    const id = new UniqueID();

    mockQuoteRepository.getById.mockResolvedValueOnce(null);
    mockTransaction.complete.mockImplementationOnce(async (fn: any) => await fn({}));

    const request = { id };
    const response = await getQuoteUseCase.execute(request);

    expect(response.isFailure).toBe(true);
    expect(response.errorValue().message).toBe("Quote not found");
  });

  it("should return a REPOSITORY_ERROR on database error", async () => {
    const id = new UniqueID();
    const error = new Error("Database error");

    mockQuoteRepository.getById.mockRejectedValueOnce(error);
    mockTransaction.complete.mockImplementationOnce(async (fn: any) => await fn({}));

    const request = { id };
    const response = await getQuoteUseCase.execute(request);

    expect(response.isFailure).toBe(true);
    expect(response.errorValue().message).toBe("Query error");
  });
});
