import type { IMapperRegistry, IPresenterRegistry, ModuleParams } from "@erp/core/api";
import {
  InMemoryMapperRegistry,
  InMemoryPresenterRegistry,
  SequelizeTransactionManager,
} from "@erp/core/api";
import {
  CreateCustomerUseCase,
  CustomerApplicationService,
  CustomerFullPresenter,
  GetCustomerUseCase,
  ListCustomersPresenter,
  ListCustomersUseCase,
  UpdateCustomerUseCase,
} from "../application";
import { CustomerDomainMapper, CustomerListMapper } from "./mappers";
import { CustomerRepository } from "./sequelize";

export type CustomerDeps = {
  transactionManager: SequelizeTransactionManager;
  mapperRegistry: IMapperRegistry;
  presenterRegistry: IPresenterRegistry;
  repo: CustomerRepository;
  service: CustomerApplicationService;
  build: {
    list: () => ListCustomersUseCase;
    get: () => GetCustomerUseCase;
    create: () => CreateCustomerUseCase;
    update: () => UpdateCustomerUseCase;
    //delete: () => DeleteCustomerUseCase;
  };
};

export function buildCustomerDependencies(params: ModuleParams): CustomerDeps {
  const { database } = params;
  const transactionManager = new SequelizeTransactionManager(database);

  // Mapper Registry
  const mapperRegistry = new InMemoryMapperRegistry();
  mapperRegistry
    .registerDomainMapper({ resource: "customer" }, new CustomerDomainMapper())
    .registerQueryMapper({ resource: "customer", query: "LIST" }, new CustomerListMapper());

  // Repository & Services
  const repo = new CustomerRepository({ mapperRegistry, database });
  const service = new CustomerApplicationService(repo);

  // Presenter Registry
  const presenterRegistry = new InMemoryPresenterRegistry();
  presenterRegistry.registerPresenters([
    {
      key: { resource: "customer", projection: "FULL" },
      presenter: new CustomerFullPresenter(presenterRegistry),
    },
    {
      key: { resource: "customer", projection: "LIST" },
      presenter: new ListCustomersPresenter(presenterRegistry),
    },
  ]);

  return {
    transactionManager,
    repo,
    mapperRegistry,
    presenterRegistry,
    service,
    build: {
      list: () => new ListCustomersUseCase(service, transactionManager, presenterRegistry),
      get: () => new GetCustomerUseCase(service, transactionManager, presenterRegistry),
      create: () => new CreateCustomerUseCase(service, transactionManager, presenterRegistry),
      update: () => new UpdateCustomerUseCase(service, transactionManager, presenterRegistry),
      //delete: () => new DeleteCustomerUseCase(_service!, transactionManager!),
    },
  };
}
