/// <reference types="jest" />
import { NotFoundException } from "@nestjs/common";
import type { Logger } from "nestjs-pino";
import { OrderOrchestrator } from "./order-orchestrator.service";
import type { SalesforceOrderService } from "@bff/integrations/salesforce/services/salesforce-order.service";
import type { OrderValidator } from "./order-validator.service";
import type { OrderBuilder } from "./order-builder.service";
import type { OrderItemBuilder } from "./order-item-builder.service";
import type { OrdersCacheService } from "./orders-cache.service";
import type { OrderDetails } from "@customer-portal/domain/orders";

const buildLogger = (): Logger =>
  ({
    log: jest.fn(),
    warn: jest.fn(),
    error: jest.fn(),
  }) as unknown as Logger;

const createOrderDetails = (overrides: Partial<OrderDetails> = {}): OrderDetails => ({
  id: "006000000000000AAA",
  orderNumber: "O-123",
  status: "Open",
  effectiveDate: new Date().toISOString(),
  totalAmount: 100,
  createdDate: new Date().toISOString(),
  lastModifiedDate: new Date().toISOString(),
  activationStatus: "Pending",
  itemsSummary: [],
  items: [],
  accountId: "001000000000000AAA",
  ...overrides,
});

describe("OrderOrchestrator.getOrderForUser", () => {
  const logger = buildLogger();
  const salesforce = {} as SalesforceOrderService;
  const orderValidator = {
    validateUserMapping: jest.fn(),
  } as unknown as OrderValidator;
  const orderBuilder = {} as OrderBuilder;
  const orderItemBuilder = {} as OrderItemBuilder;
  const ordersCache = {} as OrdersCacheService;

  const buildOrchestrator = () =>
    new OrderOrchestrator(
      logger,
      salesforce,
      orderValidator,
      orderBuilder,
      orderItemBuilder,
      ordersCache
    );

  beforeEach(() => {
    jest.resetAllMocks();
  });

  it("returns the order when the Salesforce account matches the user mapping", async () => {
    const orchestrator = buildOrchestrator();
    const expectedOrder = createOrderDetails();

    orderValidator.validateUserMapping = jest.fn().mockResolvedValue({
      userId: "user-1",
      sfAccountId: expectedOrder.accountId,
      whmcsClientId: 42,
    });
    const getOrderSpy = jest.spyOn(orchestrator, "getOrder").mockResolvedValue(expectedOrder);

    const result = await orchestrator.getOrderForUser(expectedOrder.id, "user-1");

    expect(result).toBe(expectedOrder);
    expect(getOrderSpy).toHaveBeenCalledWith(expectedOrder.id);
  });

  it("throws NotFound when the user mapping lacks a Salesforce account", async () => {
    const orchestrator = buildOrchestrator();
    orderValidator.validateUserMapping = jest.fn().mockResolvedValue({
      userId: "user-1",
      whmcsClientId: 42,
    });
    const getOrderSpy = jest.spyOn(orchestrator, "getOrder");

    await expect(orchestrator.getOrderForUser("006000000000000AAA", "user-1")).rejects.toThrow(
      NotFoundException
    );

    expect(getOrderSpy).not.toHaveBeenCalled();
  });

  it("throws NotFound when the order belongs to a different account", async () => {
    const orchestrator = buildOrchestrator();
    orderValidator.validateUserMapping = jest.fn().mockResolvedValue({
      userId: "user-1",
      sfAccountId: "001000000000000AAA",
      whmcsClientId: 42,
    });
    jest
      .spyOn(orchestrator, "getOrder")
      .mockResolvedValue(createOrderDetails({ accountId: "001000000000999ZZZ" }));

    await expect(orchestrator.getOrderForUser("006000000000000AAA", "user-1")).rejects.toThrow(
      NotFoundException
    );
  });
});
