import { TableName } from "pg-promise";
import { IMain } from "../db/types.js";
import { CrudRepository } from "./crud-repository.js";
import { PgRecordInfo, UnsavedR, SavedR, KeyType } from "./record-info.js";
import type { IDatabase } from "pg-promise";

export type PgProtocol<T> = IDatabase<T> & T;

/**
 * This function returns a constructor for a repository class for [[TRecordInfo]]
 *
 * @param aRecordType the record type runtime definition
 */
// haven't figured out a good return type for this function

export function unboundRepositoryBase<
  TRecordInfo extends PgRecordInfo,
  TDatabaseExtension
>(aRecordType: TRecordInfo) {
  return class Repository extends CrudRepository<
    UnsavedR<TRecordInfo>,
    SavedR<TRecordInfo>,
    KeyType<TRecordInfo>
  > {
    _recordType!: TRecordInfo;
    static readonly recordType = aRecordType;
    static readonly schemaName = aRecordType.schemaName;
    static readonly tableName = aRecordType.tableName;
    public readonly recordType = aRecordType;
    public readonly schemaTable: TableName;
    public db: PgProtocol<TDatabaseExtension>;
    public pgp: IMain;

    constructor(db: PgProtocol<TDatabaseExtension>) {
      super();

      this.pgp = db.$config.pgp;
      this.schemaTable = new this.pgp.helpers.TableName({
        schema: aRecordType.schemaName,
        table: aRecordType.tableName,
      });

      this.db = db;
      if (!this.db) {
        throw new Error("Missing database in repository");
      }
    }
  };
}

export function RepositoryBase<
  Rec extends PgRecordInfo,
  TDatabaseExtension = unknown
>(recordType: Rec) {
  return unboundRepositoryBase<Rec, TDatabaseExtension>(recordType);
}
