/**
 * AccountingEntry Entity - Pólizas Contables
 *
 * Registro de asientos contables con partida doble.
 *
 * @module Finance
 */

import {
  Entity,
  PrimaryGeneratedColumn,
  Column,
  CreateDateColumn,
  UpdateDateColumn,
  ManyToOne,
  OneToMany,
  JoinColumn,
  Index,
} from 'typeorm';
import { User } from '../../core/entities/user.entity';
import { AccountingEntryLine } from './accounting-entry-line.entity';

export type EntryType =
  | 'purchase'
  | 'sale'
  | 'payment'
  | 'collection'
  | 'payroll'
  | 'adjustment'
  | 'depreciation'
  | 'transfer'
  | 'opening'
  | 'closing';

export type EntryStatus = 'draft' | 'pending_approval' | 'approved' | 'posted' | 'cancelled' | 'reversed';

@Entity('accounting_entries', { schema: 'finance' })
@Index(['tenantId', 'entryNumber'], { unique: true })
@Index(['tenantId', 'entryDate'])
@Index(['tenantId', 'status'])
@Index(['tenantId', 'sourceModule', 'sourceId'])
export class AccountingEntry {
  @PrimaryGeneratedColumn('uuid')
  id!: string;

  @Column({ name: 'tenant_id', type: 'uuid' })
  @Index()
  tenantId!: string;

  // Número de póliza
  @Column({ name: 'entry_number', length: 50 })
  entryNumber!: string;

  // Tipo y fecha
  @Column({
    name: 'entry_type',
    type: 'enum',
    enum: ['purchase', 'sale', 'payment', 'collection', 'payroll', 'adjustment', 'depreciation', 'transfer', 'opening', 'closing'],
    enumName: 'entry_type',
  })
  entryType!: EntryType;

  @Column({ name: 'entry_date', type: 'date' })
  entryDate!: Date;

  @Column({
    type: 'enum',
    enum: ['draft', 'pending_approval', 'approved', 'posted', 'cancelled', 'reversed'],
    enumName: 'entry_status',
    default: 'draft',
  })
  status!: EntryStatus;

  // Descripción
  @Column({ type: 'text' })
  description!: string;

  @Column({ length: 255, nullable: true })
  reference?: string;

  // Origen (módulo que generó la póliza)
  @Column({ name: 'source_module', length: 50, nullable: true })
  sourceModule?: string;

  @Column({ name: 'source_id', type: 'uuid', nullable: true })
  sourceId?: string;

  // Proyecto asociado
  @Column({ name: 'project_id', type: 'uuid', nullable: true })
  projectId?: string;

  // Periodo contable
  @Column({ name: 'fiscal_year', type: 'int' })
  fiscalYear!: number;

  @Column({ name: 'fiscal_period', type: 'int' })
  fiscalPeriod!: number;

  // Totales (calculados)
  @Column({
    name: 'total_debit',
    type: 'decimal',
    precision: 18,
    scale: 2,
    default: 0,
  })
  totalDebit!: number;

  @Column({
    name: 'total_credit',
    type: 'decimal',
    precision: 18,
    scale: 2,
    default: 0,
  })
  totalCredit!: number;

  @Column({ name: 'is_balanced', type: 'boolean', default: false })
  isBalanced!: boolean;

  // Moneda
  @Column({ length: 3, default: 'MXN' })
  currency!: string;

  @Column({
    name: 'exchange_rate',
    type: 'decimal',
    precision: 12,
    scale: 6,
    default: 1,
  })
  exchangeRate!: number;

  // Aprobación
  @Column({ name: 'approved_by_id', type: 'uuid', nullable: true })
  approvedById?: string;

  @ManyToOne(() => User, { nullable: true })
  @JoinColumn({ name: 'approved_by_id' })
  approvedBy?: User;

  @Column({ name: 'approved_at', type: 'timestamptz', nullable: true })
  approvedAt?: Date;

  // Contabilización
  @Column({ name: 'posted_at', type: 'timestamptz', nullable: true })
  postedAt?: Date;

  @Column({ name: 'posted_by_id', type: 'uuid', nullable: true })
  postedById?: string;

  // Reversión
  @Column({ name: 'reversed_entry_id', type: 'uuid', nullable: true })
  reversedEntryId?: string;

  @Column({ name: 'reversal_reason', type: 'text', nullable: true })
  reversalReason?: string;

  // Líneas de la póliza
  @OneToMany(() => AccountingEntryLine, (line) => line.entry, { cascade: true })
  lines?: AccountingEntryLine[];

  // Notas y metadatos
  @Column({ type: 'text', nullable: true })
  notes?: string;

  @Column({ type: 'jsonb', nullable: true })
  metadata?: Record<string, any>;

  // Auditoría
  @Column({ name: 'created_by', type: 'uuid', nullable: true })
  createdBy?: string;

  @Column({ name: 'updated_by', type: 'uuid', nullable: true })
  updatedBy?: string;

  @CreateDateColumn({ name: 'created_at', type: 'timestamptz' })
  createdAt!: Date;

  @UpdateDateColumn({ name: 'updated_at', type: 'timestamptz' })
  updatedAt!: Date;

  @Column({ name: 'deleted_at', type: 'timestamptz', nullable: true })
  deletedAt?: Date;
}
