import { ISequelizeAdapter, SequelizeRepository } from "@/contexts/common/infrastructure/sequelize";
import { ICollection, IQueryCriteria, UniqueID } from "@shared/contexts";
import { Transaction } from "sequelize";

import { IDealerRepository } from "../domain";
import { Dealer } from "../domain/entities";
import { ISalesContext } from "./Sales.context";
import { IDealerMapper, createDealerMapper } from "./mappers";

export type QueryParams = {
  pagination: Record<string, any>;
  filters: Record<string, any>;
};

export class DealerRepository extends SequelizeRepository<Dealer> implements IDealerRepository {
  protected mapper: IDealerMapper;

  public constructor(props: {
    mapper: IDealerMapper;
    adapter: ISequelizeAdapter;
    transaction: Transaction;
  }) {
    const { adapter, mapper, transaction } = props;
    super({ adapter, transaction });
    this.mapper = mapper;
  }

  public async exists(id: UniqueID): Promise<boolean> {
    return this._exists("Dealer_Model", "id", id.toPrimitive());
  }

  public async create(user: Dealer): Promise<void> {
    const userData = this.mapper.mapToPersistence(user);
    await this._save("Dealer_Model", user.id, userData);
  }

  public async update(user: Dealer): Promise<void> {
    const userData = this.mapper.mapToPersistence(user);

    // borrando y luego creando
    // await this.removeById(user.id, true);
    await this._save("Dealer_Model", user.id, userData, {});
  }

  public async getById(id: UniqueID): Promise<Dealer | null> {
    const rawDealer: any = await this._getById("Dealer_Model", id);

    if (!rawDealer === true) {
      return null;
    }

    return this.mapper.mapToDomain(rawDealer);
  }

  public async getByUserId(userId: UniqueID): Promise<Dealer | null> {
    const rawDealer: any = await this._getBy("Dealer_Model", "user_id", userId.toPrimitive());

    if (!rawDealer === true) {
      return null;
    }

    return this.mapper.mapToDomain(rawDealer);
  }

  public async findAll(queryCriteria?: IQueryCriteria): Promise<ICollection<any>> {
    const { rows, count } = await this._findAll("Dealer_Model", queryCriteria, {
      include: [], // esto es para quitar las asociaciones al hacer la consulta
    });

    return this.mapper.mapArrayAndCountToDomain(rows, count);
  }

  public async removeById(id: UniqueID, force: boolean = false): Promise<void> {
    return this._removeById("Dealer_Model", id);
  }
}

export const registerDealerRepository = (context: ISalesContext) => {
  const adapter = context.adapter;
  const repoManager = context.repositoryManager;

  repoManager.registerRepository("Dealer", (params = { transaction: null }) => {
    const { transaction } = params;

    return new DealerRepository({
      transaction,
      adapter,
      mapper: createDealerMapper(context),
    });
  });
};
