import { BaseEntity } from "@edr/api-common";
import { Freight } from "@edr/types";
import { Column, Entity, Index, JoinColumn, ManyToOne } from "typeorm";
import { PaymentEntity } from "../../payment/entities/payment.entity";
import { Company } from "../../companies/entities/company.entity";
import { CompanyProfile } from "../../companies/entities/company-profile.entity";

/** A single recorded settlement against an invoice (payment ledger entry). */
export interface InvoicePayment {
  amount: number;
  method?: string | null;
  reference?: string | null;
  /** ISO timestamp of when the settlement was recorded. */
  paidAt: string;
  metadata?: Record<string, unknown> | null;
}

@Entity({ schema: "freight", name: "invoices" })
@Index(["companyId"])
@Index(["companyProfileId"])
export class Invoice extends BaseEntity {
  @Column({ name: "invoice_number", type: "varchar", length: 64, unique: true })
  invoiceNumber!: string;

  /** The customer (company) this invoice is billed to. */
  @Column({ name: "company_id", type: "uuid" })
  companyId!: string;

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

  /** The specific company profile (importer/exporter/forwarder/...) billed. */
  @Column({ name: "company_profile_id", type: "uuid" })
  companyProfileId!: string;

  @ManyToOne(() => CompanyProfile)
  @JoinColumn({ name: "company_profile_id" })
  companyProfile?: CompanyProfile;

  /** Sum of line amounts before tax; defaults to `totalAmount` for tax-free invoices. */
  @Column({ name: "subtotal_amount", type: "numeric", precision: 14, scale: 2, default: 0 })
  subtotalAmount!: number;

  @Column({ name: "tax_amount", type: "numeric", precision: 14, scale: 2, default: 0 })
  taxAmount!: number;

  @Column({ name: "total_amount", type: "numeric", precision: 14, scale: 2 })
  totalAmount!: number;

  /** Cumulative amount settled so far (supports partial payment). */
  @Column({ name: "paid_amount", type: "numeric", precision: 14, scale: 2, default: 0 })
  paidAmount!: number;

  /** Outstanding balance = `totalAmount - paidAmount` (0 once fully paid). */
  @Column({ name: "balance_amount", type: "numeric", precision: 14, scale: 2, default: 0 })
  balanceAmount!: number;

  @Column({ name: "currency", type: "varchar", length: 8, default: "ETB" })
  currency!: string;

  @Column({
    name: "status",
    type: "enum",
    enum: Freight.InvoiceStatus,
    default: Freight.InvoiceStatus.Draft,
  })
  status!: Freight.InvoiceStatus;

  /** The source of the payment (e.g. booking, customer, etc.). */
  @Column({ name: "source", type: "varchar", length: 255, nullable: false })
  source!: string;

  /** The ID of the source (e.g. booking ID, customer ID, etc.). */
  @Column({ name: "source_id", type: "varchar", length: 255, nullable: false })
  sourceId!: string;

  /** The type of Invoice (e.g. prepaid, credit, etc.). it suppose to answer the question "what is the invoice for?" */
  @Column({
    type: "varchar",
    length: 255,
    nullable: false,
  })
  type!: string;

  /** Set when the invoice is actually issued (DRAFT invoices leave this null). */
  @Column({ name: "issued_at", type: "timestamptz", nullable: true })
  issuedAt?: Date | null;

  /** Set when the invoice is fully settled. */
  @Column({ name: "paid_at", type: "timestamptz", nullable: true })
  paidAt?: Date | null;

  /** Ledger of individual settlements (manual or gateway), newest last. */
  @Column({ name: "payments", type: "jsonb", default: () => "'[]'" })
  payments!: InvoicePayment[];

  /** The ID of the payment that generated this invoice. */
  @Column({ name: "payment_id", type: "uuid", nullable: true })
  paymentId?: string | null;

  @ManyToOne(() => PaymentEntity)
  @JoinColumn({ name: "payment_id" })
  payment?: PaymentEntity;

  @Column({ name: "due_at", type: "timestamptz" })
  dueAt!: Date;
}
