import { Collection, Result, ResultCollection } from "@repo/rdx-utils";
import { Model } from "sequelize";
import { MapperParamsType } from "../../../domain";
import { ISequelizeDomainMapper } from "./sequelize-mapper.interface";

export abstract class SequelizeDomainMapper<TModel extends Model, TModelAttributes, TEntity>
  implements ISequelizeDomainMapper<TModel, TModelAttributes, TEntity>
{
  public abstract mapToDomain(raw: TModel, params?: MapperParamsType): Result<TEntity, Error>;
  public abstract mapToPersistence(
    domain: TEntity,
    params?: MapperParamsType
  ): Result<TModelAttributes, Error>;

  public mapToDomainCollection(
    raws: (TModel | TModelAttributes)[],
    totalCount: number,
    params?: MapperParamsType
  ): Result<Collection<TEntity>, Error> {
    const _source = raws ?? [];

    try {
      if (_source.length === 0) {
        return Result.ok(new Collection([], totalCount));
      }

      const items = _source.map(
        (value, index) => this.mapToDomain(value as TModel, { index, ...params }).data
      );
      return Result.ok(new Collection(items, totalCount));
    } catch (error) {
      return Result.fail(error as Error);
    }
  }

  public mapToPersistenceArray(
    domains: Collection<TEntity>,
    params?: MapperParamsType
  ): Result<TModelAttributes[], Error> {
    const results = new ResultCollection(
      domains.map((domain, index) => this.mapToPersistence(domain, { index, ...params }))
    );
    if (results.hasSomeFaultyResult()) return results.getFirstFaultyResult();

    return Result.ok(results.objects);
  }
}
