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

import { JsonTaxCatalogProvider, SpainTaxCatalogProvider } from "@erp/core";
import type { IMapperRegistry, IPresenterRegistry, ModuleParams } from "@erp/core/api";
import {
  InMemoryMapperRegistry,
  InMemoryPresenterRegistry,
  SequelizeTransactionManager,
} from "@erp/core/api";
import {
  ChangeStatusCustomerInvoiceUseCase,
  CreateCustomerInvoiceUseCase,
  CustomerInvoiceApplicationService,
  CustomerInvoiceFullPresenter,
  CustomerInvoiceItemsFullPresenter,
  CustomerInvoiceItemsReportPersenter,
  CustomerInvoiceReportHTMLPresenter,
  CustomerInvoiceReportPDFPresenter,
  CustomerInvoiceReportPresenter,
  GetCustomerInvoiceUseCase,
  IssueCustomerInvoiceUseCase,
  ListCustomerInvoicesPresenter,
  ListCustomerInvoicesUseCase,
  RecipientInvoiceFullPresenter,
  ReportCustomerInvoiceUseCase,
  UpdateCustomerInvoiceUseCase,
} from "../application";
import { CustomerInvoiceDomainMapper, CustomerInvoiceListMapper } from "./mappers";
import { CustomerInvoiceRepository } from "./sequelize";
import { SequelizeInvoiceNumberGenerator } from "./services";

export type CustomerInvoiceDeps = {
  transactionManager: SequelizeTransactionManager;
  mapperRegistry: IMapperRegistry;
  presenterRegistry: IPresenterRegistry;
  repo: CustomerInvoiceRepository;
  appService: CustomerInvoiceApplicationService;
  catalogs: {
    taxes: JsonTaxCatalogProvider;
  };
  useCases: {
    list: () => ListCustomerInvoicesUseCase;
    get: () => GetCustomerInvoiceUseCase;
    create: () => CreateCustomerInvoiceUseCase;
    update: () => UpdateCustomerInvoiceUseCase;
    //delete: () => DeleteCustomerInvoiceUseCase;
    report: () => ReportCustomerInvoiceUseCase;
    issue: () => IssueCustomerInvoiceUseCase;
    changeStatus: () => ChangeStatusCustomerInvoiceUseCase;
  };
};

export function buildCustomerInvoiceDependencies(params: ModuleParams): CustomerInvoiceDeps {
  const { database } = params;

  /** Dominio */
  const catalogs = { taxes: SpainTaxCatalogProvider() };

  /** Infraestructura */
  const transactionManager = new SequelizeTransactionManager(database);

  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 repository = new CustomerInvoiceRepository({ mapperRegistry, database });
  const numberGenerator = new SequelizeInvoiceNumberGenerator();

  /** Aplicación */
  const appService = new CustomerInvoiceApplicationService(repository, numberGenerator);

  // 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),
    },
  ]);

  const useCases = {
    list: () => new ListCustomerInvoicesUseCase(appService, transactionManager, presenterRegistry),
    get: () => new GetCustomerInvoiceUseCase(appService, transactionManager, presenterRegistry),
    create: () =>
      new CreateCustomerInvoiceUseCase(
        appService,
        transactionManager,
        presenterRegistry,
        catalogs.taxes
      ),
    update: () =>
      new UpdateCustomerInvoiceUseCase(appService, transactionManager, presenterRegistry),
    report: () =>
      new ReportCustomerInvoiceUseCase(appService, transactionManager, presenterRegistry),
    issue: () => new IssueCustomerInvoiceUseCase(appService, transactionManager, presenterRegistry),
    changeStatus: () => new ChangeStatusCustomerInvoiceUseCase(appService, transactionManager),
  };

  return {
    transactionManager,
    repo: repository,
    mapperRegistry,
    presenterRegistry,
    appService,
    catalogs,
    useCases,
  };
}
