import {
  GeneratedQuotes,
  Opportunity,
  Role,
  User,
} from "../../generated/prisma/client";
import { prisma } from "../constants";
import { OpportunityController } from "./OpportunityController";
import UserController from "./UserController";

export class GeneratedQuoteController {
  public readonly id: string;

  public quoteRegenData: unknown;
  public quoteRegenParams: unknown;
  public quoteRegenHash: string;

  public downloads: unknown[];

  public quoteFile: Uint8Array;
  public quoteFileName: string;

  public opportunityId: string;
  public createdById: string | null;

  public createdAt: Date;
  public updatedAt: Date;

  private _opportunity: OpportunityController | null;
  private _createdBy: UserController | null;

  constructor(
    data: GeneratedQuotes & {
      opportunity?: Opportunity | null;
      createdBy?: (User & { roles: Role[] }) | null;
    }
  ) {
    this.id = data.id;

    this.quoteRegenData = data.quoteRegenData;
    this.quoteRegenParams = data.quoteRegenParams;
    this.quoteRegenHash = data.quoteRegenHash;

    this.downloads = Array.isArray(data.downloads)
      ? (data.downloads as unknown[])
      : [];

    this.quoteFile = data.quoteFile;
    this.quoteFileName = data.quoteFileName;

    this.opportunityId = data.opportunityId;
    this.createdById = data.createdById;

    this.createdAt = data.createdAt;
    this.updatedAt = data.updatedAt;

    this._opportunity = data.opportunity
      ? new OpportunityController(data.opportunity)
      : null;

    this._createdBy = data.createdBy
      ? new UserController(data.createdBy)
      : null;
  }

  public async fetchOpportunity(): Promise<OpportunityController | null> {
    if (this._opportunity) return this._opportunity;

    const opportunity = await prisma.opportunity.findFirst({
      where: { uid: this.opportunityId },
    });

    if (!opportunity) return null;

    this._opportunity = new OpportunityController(opportunity);
    return this._opportunity;
  }

  public async fetchCreatedBy(): Promise<UserController | null> {
    if (this._createdBy) return this._createdBy;
    if (!this.createdById) return null;

    const user = await prisma.user.findFirst({
      where: { id: this.createdById },
      include: { roles: true },
    });

    if (!user) return null;

    this._createdBy = new UserController(user);
    return this._createdBy;
  }

  public toJson(opts?: {
    includeFile?: boolean;
    encodeFileAsBase64?: boolean;
    includeRegenData?: boolean;
    includeRegenParams?: boolean;
    includeDownloads?: boolean;
    includeOpportunity?: boolean;
    includeCreatedBy?: boolean;
  }): Record<string, any> {
    return {
      id: this.id,
      quoteFileName: this.quoteFileName,
      quoteRegenHash: this.quoteRegenHash,
      opportunityId: this.opportunityId,
      createdById: this.createdById,
      downloads: opts?.includeDownloads ? this.downloads : undefined,
      quoteRegenData: opts?.includeRegenData ? this.quoteRegenData : undefined,
      quoteRegenParams: opts?.includeRegenParams
        ? this.quoteRegenParams
        : undefined,
      quoteFile: !opts?.includeFile
        ? undefined
        : opts?.encodeFileAsBase64
        ? Buffer.from(this.quoteFile).toString("base64")
        : this.quoteFile,
      opportunity:
        opts?.includeOpportunity && this._opportunity
          ? this._opportunity.toJson()
          : undefined,
      createdBy:
        opts?.includeCreatedBy && this._createdBy
          ? this._createdBy.toJson()
          : undefined,
      createdAt: this.createdAt,
      updatedAt: this.updatedAt,
    };
  }
}
