import { BaseEntity } from "@edr/api-common";
import { Column, Entity, Index, JoinColumn, ManyToOne } from "typeorm";
import { Company } from "./company.entity";

/**
 * Lifecycle of a customer's proposed profile change. Edits made on the portal
 * settings page by an already-approved company are staged here (not written to
 * the live Company row) until a backoffice reviewer approves — at which point
 * the snapshot is applied — or rejects with a note, after which the customer can
 * amend and resubmit.
 */
export enum ChangeRequestStatus {
  Pending = "pending",
  Approved = "approved",
  Rejected = "rejected",
}

/**
 * A single staged business-license change on one company profile, awaiting
 * review. `add` → a new file was uploaded under the pending code and becomes
 * live on approval; `remove` → an existing live file is deleted on approval.
 * A "replace" is recorded as a `remove` of the old file plus an `add` of the
 * new one. `fileId` is the FileRecord id the op targets.
 */
export interface LicenseChangeIntent {
  profileId: string;
  op: "add" | "remove";
  fileId: string;
  /** File name, snapshotted for the backoffice review screen. */
  fileName?: string;
}

/**
 * A staged change to a company-level document, awaiting review. Same semantics
 * as {@link LicenseChangeIntent} but keyed by the document's FileRecord `code`
 * (e.g. `poa_delegation_letter`) rather than a profile: `add` → uploaded under
 * the pending code, promoted to `code` on approval; `remove` → a live file that
 * is deleted on approval. A replace is a `remove` plus an `add`.
 */
export interface DocumentChangeIntent {
  op: "add" | "remove";
  fileId: string;
  /** The live FileRecord code this op targets (the upload setting's fileKey). */
  code: string;
  /** File name, snapshotted for the backoffice review screen. */
  fileName?: string;
}

/** File references staged alongside a change request (documents/licenses). */
export interface ChangeRequestDocuments {
  /**
   * FileRecord ids uploaded against the company while this request was open.
   * These go live immediately — only their ids are recorded, for the reviewer.
   * Contrast `documentChanges`, which stages the file behind the pending code.
   */
  documentFileIds?: string[];
  /** Staged per-profile business-license add/remove intents. */
  licenseChanges?: LicenseChangeIntent[];
  /** Staged company-level document add/remove intents (e.g. the PoA letter). */
  documentChanges?: DocumentChangeIntent[];
}

@Entity({ schema: "freight", name: "company_change_request" })
@Index(["companyId"])
@Index(["status"])
export class CompanyChangeRequest extends BaseEntity {
  @Column({ name: "company_id", type: "uuid" })
  companyId!: string;

  @ManyToOne(() => Company, { onDelete: "CASCADE" })
  @JoinColumn({ name: "company_id" })
  company?: Company;

  /**
   * Proposed profile field values, shaped as `Partial<UpdateProfileDto>`. Covers
   * the Company / Contact / General Manager / Power-of-Attorney tabs (contact/GM/
   * PoA fields land in `Company.attributes` on approval).
   */
  @Column({ name: "snapshot", type: "jsonb" })
  snapshot!: Record<string, any>;

  /** Staged document/license file references (see {@link ChangeRequestDocuments}). */
  @Column({ name: "documents", type: "jsonb", nullable: true })
  documents?: ChangeRequestDocuments | null;

  @Column({
    name: "status",
    type: "varchar",
    length: 20,
    default: ChangeRequestStatus.Pending,
  })
  status!: ChangeRequestStatus;

  /** Backoffice reviewer's rejection note. */
  @Column({ name: "note", type: "text", nullable: true })
  note?: string | null;

  @Column({ name: "submitted_by", type: "uuid", nullable: true })
  submittedBy?: string | null;

  @Column({ name: "submitted_at", type: "timestamptz", nullable: true })
  submittedAt?: Date | null;

  @Column({ name: "reviewed_by", type: "uuid", nullable: true })
  reviewedBy?: string | null;

  @Column({ name: "reviewed_at", type: "timestamptz", nullable: true })
  reviewedAt?: Date | null;
}
