import { Entity, Column, Index, ManyToOne, JoinColumn, OneToMany } from 'typeorm';
import { BaseEntity } from '../database/base.entity';
import { BankAccountEntity } from './bank-account.entity';
import { CurrencyEntity } from './currency.entity';
import { SupplierEntity } from './supplier.entity';
import { SettlementPaymentEntity, SettlementPaymentMode } from './settlement-payment.entity';
import { SettlementPaymentType } from '../common/constants/settlement-payment-type';

/**
 * §12e — what happens to money paid above the allocated invoices.
 *
 *   PREPAYMENT  parked on the supplier's credit ledger and offered
 *               back on the next voucher for that (supplier, currency)
 *   ADVANCE     tracked on this voucher only; not drawdownable
 */
export enum PayoutExcessTreatment {
  PREPAYMENT = 'PREPAYMENT',
  ADVANCE = 'ADVANCE',
}

/**
 * Supplier Payout — supplier-side mirror of PaymentCollectionEntity.
 * One row per Pay Supplier screen submission that allocates a single
 * paid amount across N supplier-side settlements (across N bookings +
 * service types) for one supplier.
 *
 * Receipt model: one payout = one voucher_no with the `PAY-` prefix.
 * Child settlement_payments rows reference it via `payout_id` and
 * inherit the voucher_no (we reuse the same `receipt_no` column on
 * settlement_payments — the schema doesn't care, the customer/supplier
 * direction is encoded by which parent the row links to).
 *
 * Append-only with admin-only void, matching payment_collections.
 */
@Entity('supplier_payouts')
@Index(['tenant_id', 'supplier_id', 'payment_date'])
@Index(['tenant_id', 'payment_date'])
@Index(['tenant_id', 'voucher_year', 'voucher_no'], { unique: true })
export class SupplierPayoutEntity extends BaseEntity {
  @Column({ type: 'varchar', length: 20 })
  voucher_no: string;

  @Column({ type: 'int' })
  voucher_year: number;

  @ManyToOne(() => SupplierEntity)
  @JoinColumn({ name: 'supplier_id' })
  supplier: SupplierEntity;

  @Column({ type: 'uuid' })
  supplier_id: string;

  /** Snapshot of the supplier name at payout-time so historical
   *  vouchers stay readable even if the supplier record changes. */
  @Column({ type: 'varchar', length: 200, nullable: true })
  supplier_name: string | null;

  @Column({ type: 'date' })
  payment_date: string;

  @Column({ type: 'varchar', length: 32 })
  mode: SettlementPaymentMode;

  @Column({ type: 'varchar', length: 100, nullable: true })
  ref_no: string | null;

  /**
   * Optional debit / credit bank accounts on every payment mode.
   * Either side may be null. When both are set the IDs must differ.
   */
  @ManyToOne(() => BankAccountEntity, { nullable: true })
  @JoinColumn({ name: 'debit_bank_account_id' })
  debit_bank_account: BankAccountEntity | null;

  @Column({ type: 'uuid', nullable: true })
  debit_bank_account_id: string | null;

  @ManyToOne(() => BankAccountEntity, { nullable: true })
  @JoinColumn({ name: 'credit_bank_account_id' })
  credit_bank_account: BankAccountEntity | null;

  @Column({ type: 'uuid', nullable: true })
  credit_bank_account_id: string | null;

  @ManyToOne(() => CurrencyEntity)
  @JoinColumn({ name: 'currency_id' })
  currency: CurrencyEntity;

  @Column({ type: 'uuid' })
  currency_id: string;

  /** Operator's stated intent — allocate against bills, or park the
   *  whole amount as a deposit on the supplier's ledger. */
  @Column({ type: 'varchar', length: 16, default: SettlementPaymentType.BILL_TO_BILL })
  payment_type: SettlementPaymentType;

  @Column({ type: 'decimal', precision: 12, scale: 2 })
  paid_amount: number;

  /** Sum of allocations across child settlement_payments. Maintained
   *  by the service in the same transaction as the child writes. */
  @Column({ type: 'decimal', precision: 12, scale: 2, default: 0 })
  allocated_amount: number;

  /** Prepayment drawn down from the supplier's credit ledger and spent
   *  on this voucher alongside fresh cash. Allocation cap is
   *  `paid_amount + credit_applied`. */
  @Column({ type: 'decimal', precision: 12, scale: 2, default: 0 })
  credit_applied: number;

  /** (paid_amount + credit_applied) - allocated_amount, set when ops
   *  pays more than the outstanding invoices total. `excess_treatment`
   *  decides whether it lands on the supplier's prepayment ledger. */
  @Column({ type: 'decimal', precision: 12, scale: 2, default: 0 })
  excess_amount: number;

  @Column({ type: 'varchar', length: 16, nullable: true })
  excess_treatment: PayoutExcessTreatment | null;

  @Column({ type: 'text', nullable: true })
  notes: string | null;

  // ── Void (admin-only, mirrors payment_collections) ──────────────
  @Column({ type: 'boolean', default: false })
  is_void: boolean;

  @Column({ type: 'timestamptz', nullable: true })
  voided_at: Date | null;

  @Column({ type: 'uuid', nullable: true })
  voided_by: string | null;

  @Column({ type: 'text', nullable: true })
  void_reason: string | null;

  @OneToMany(() => SettlementPaymentEntity, (p) => p.payout_id)
  payments: SettlementPaymentEntity[];
}
