// modules/invoice/infrastructure/invoice-dependencies.factory.ts

import type { IMapperRegistry, IPresenterRegistry, ModuleParams } from "@erp/core/api";

import {
  InMemoryMapperRegistry,
  InMemoryPresenterRegistry,
  SequelizeTransactionManager,
} from "@erp/core/api";

import {
  CreateCustomerInvoiceUseCase,
  CustomerInvoiceFullPresenter,
  CustomerInvoiceItemsFullPresenter,
  CustomerInvoiceReportHTMLPresenter,
  CustomerInvoiceReportPDFPresenter,
  CustomerInvoiceReportPresenter,
  GetCustomerInvoiceUseCase,
  ListCustomerInvoicesPresenter,
  ListCustomerInvoicesUseCase,
  RecipientInvoiceFullPresenter,
  ReportCustomerInvoiceUseCase,
  UpdateCustomerInvoiceUseCase,
} from "../application";

import { JsonTaxCatalogProvider, SpainTaxCatalogProvider } from "@erp/core";
import {
  CustomerInvoiceApplicationService,
  CustomerInvoiceItemsReportPersenter,
} from "../application";
import { CustomerInvoiceDomainMapper, CustomerInvoiceListMapper } from "./mappers";
import { CustomerInvoiceRepository } from "./sequelize";

export type CustomerInvoiceDeps = {
  transactionManager: SequelizeTransactionManager;
  mapperRegistry: IMapperRegistry;
  presenterRegistry: IPresenterRegistry;
  repo: CustomerInvoiceRepository;
  service: CustomerInvoiceApplicationService;
  catalogs: {
    taxes: JsonTaxCatalogProvider;
  };
  build: {
    list: () => ListCustomerInvoicesUseCase;
    get: () => GetCustomerInvoiceUseCase;
    create: () => CreateCustomerInvoiceUseCase;
    update: () => UpdateCustomerInvoiceUseCase;
    //delete: () => DeleteCustomerInvoiceUseCase;
    report: () => ReportCustomerInvoiceUseCase;
  };
  getService: (name: string) => any;
  listServices: () => string[];
};

export function buildCustomerInvoiceDependencies(params: ModuleParams): CustomerInvoiceDeps {
  const { database, listServices, getService } = params;
  const transactionManager = new SequelizeTransactionManager(database);
  const catalogs = { taxes: SpainTaxCatalogProvider() };

  // Mapper Registry
  const mapperRegistry = new InMemoryMapperRegistry();
  mapperRegistry
    .registerDomainMapper(
      { resource: "customer-invoice" },
      new CustomerInvoiceDomainMapper({ taxCatalog: catalogs.taxes })
    )
    .registerQueryMappers([
      {
        key: { resource: "customer-invoice", query: "LIST" },
        mapper: new CustomerInvoiceListMapper(),
      },
    ]);

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

  // Presenter Registry
  const presenterRegistry = new InMemoryPresenterRegistry();
  presenterRegistry.registerPresenters([
    {
      key: {
        resource: "customer-invoice-items",
        projection: "FULL",
      },
      presenter: new CustomerInvoiceItemsFullPresenter(presenterRegistry),
    },
    {
      key: {
        resource: "recipient-invoice",
        projection: "FULL",
      },
      presenter: new RecipientInvoiceFullPresenter(presenterRegistry),
    },
    {
      key: {
        resource: "customer-invoice",
        projection: "FULL",
      },
      presenter: new CustomerInvoiceFullPresenter(presenterRegistry),
    },
    {
      key: {
        resource: "customer-invoice",
        projection: "LIST",
      },
      presenter: new ListCustomerInvoicesPresenter(presenterRegistry),
    },
    {
      key: {
        resource: "customer-invoice",
        projection: "REPORT",
        format: "JSON",
      },
      presenter: new CustomerInvoiceReportPresenter(presenterRegistry),
    },
    {
      key: {
        resource: "customer-invoice-items",
        projection: "REPORT",
        format: "JSON",
      },
      presenter: new CustomerInvoiceItemsReportPersenter(presenterRegistry),
    },
    {
      key: {
        resource: "customer-invoice",
        projection: "REPORT",
        format: "HTML",
      },
      presenter: new CustomerInvoiceReportHTMLPresenter(presenterRegistry),
    },
    {
      key: {
        resource: "customer-invoice",
        projection: "REPORT",
        format: "PDF",
      },
      presenter: new CustomerInvoiceReportPDFPresenter(presenterRegistry),
    },
  ]);

  return {
    transactionManager,
    repo,
    mapperRegistry,
    presenterRegistry,
    service,
    catalogs,
    build: {
      list: () => new ListCustomerInvoicesUseCase(service, transactionManager, presenterRegistry),
      get: () => new GetCustomerInvoiceUseCase(service, transactionManager, presenterRegistry),
      create: () =>
        new CreateCustomerInvoiceUseCase(
          service,
          transactionManager,
          presenterRegistry,
          catalogs.taxes
        ),
      update: () =>
        new UpdateCustomerInvoiceUseCase(service, transactionManager, presenterRegistry),
      // delete: () => new DeleteCustomerInvoiceUseCase(service, transactionManager),
      report: () =>
        new ReportCustomerInvoiceUseCase(service, transactionManager, presenterRegistry),
    },
    listServices,
    getService,
  };
}
