import { IUseCase, IUseCaseError, UseCaseError } from "@/contexts/common/application/useCases";
import { IRepositoryManager } from "@/contexts/common/domain";
import { Collection, Filter, ICollection, IQueryCriteria, Result } from "@shared/contexts";

import { IInfrastructureError } from "@/contexts/common/infrastructure";
import { ISequelizeAdapter } from "@/contexts/common/infrastructure/sequelize";
import { Dealer, Quote } from "../../domain";
import { IQuoteRepository } from "../../domain/repository";
import { ISalesContext } from "../../infrastructure";

export interface IListQuotesParams {
  queryCriteria: IQueryCriteria;
}

export type ListQuotesResult =
  | Result<never, IUseCaseError> // Misc errors (value objects)
  | Result<ICollection<Quote>, never>; // Success!

export class ListQuotesUseCase implements IUseCase<IListQuotesParams, Promise<ListQuotesResult>> {
  private _adapter: ISequelizeAdapter;
  private _repositoryManager: IRepositoryManager;
  private _dealer?: Dealer;

  constructor(context: ISalesContext) {
    this._adapter = context.adapter;
    this._repositoryManager = context.repositoryManager;
    this._dealer = context.dealer;
  }

  async execute(params: Partial<IListQuotesParams>): Promise<ListQuotesResult> {
    const { queryCriteria } = params;

    if (this._dealer) {
      queryCriteria?.filters.add(
        Filter.create({
          operator: "eq",
          field: "dealer_id",
          value: this._dealer.id,
        }).object,
        "AND"
      );
    }

    console.log(queryCriteria?.toJSON());

    return this.findQuotes(queryCriteria);
  }

  private async findQuotes(queryCriteria) {
    const transaction = this._adapter.startTransaction();
    const QuoteRepoBuilder = this._getQuoteRepository();

    let Quotes: ICollection<Quote> = new Collection();

    try {
      await transaction.complete(async (t) => {
        Quotes = await QuoteRepoBuilder({ transaction: t }).findAll(queryCriteria);
      });
      return Result.ok(Quotes);
    } catch (error: unknown) {
      const _error = error as IInfrastructureError;
      console.trace(_error.message);
      return Result.fail(UseCaseError.create(UseCaseError.REPOSITORY_ERROR, "Query error", _error));
    }
  }

  private _getQuoteRepository() {
    return this._repositoryManager.getRepository<IQuoteRepository>("Quote");
  }
}
