import {
  Entity,
  PrimaryGeneratedColumn,
  Column,
  CreateDateColumn,
  UpdateDateColumn,
  Index,
  OneToMany,
  ManyToOne,
  JoinColumn,
  DeleteDateColumn,
} from 'typeorm';
import { CfdiStatus } from '../enums/cfdi-status.enum.js';
import { CfdiLog } from './cfdi-log.entity.js';
import { CfdiCancellation } from './cfdi-cancellation.entity.js';

/**
 * Voucher type enum aligned with DDL fiscal.cfdi_voucher_type
 */
export enum CfdiVoucherType {
  INGRESO = 'I',
  EGRESO = 'E',
  TRASLADO = 'T',
  NOMINA = 'N',
  PAGO = 'P',
}

/**
 * CFDI Invoice Entity
 * Aligned with DDL: fiscal.cfdi_invoices
 */
@Entity({ schema: 'fiscal', name: 'cfdi_invoices' })
@Index('idx_cfdi_invoices_tenant', ['tenantId'])
@Index('idx_cfdi_invoices_uuid', ['uuid'], { unique: true, where: 'uuid IS NOT NULL' })
@Index('idx_cfdi_invoices_invoice', ['invoiceId'])
@Index('idx_cfdi_invoices_status', ['status'])
@Index('idx_cfdi_invoices_issuer', ['issuerRfc'])
@Index('idx_cfdi_invoices_receiver', ['receiverRfc'])
@Index('idx_cfdi_invoices_folio', ['serie', 'folio'])
@Index('idx_cfdi_invoices_stamp_date', ['stampDate'])
export class CfdiInvoice {
  @PrimaryGeneratedColumn('uuid')
  id: string;

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

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

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

  // CFDI Identity
  @Column({ type: 'varchar', length: 36, nullable: true })
  uuid: string | null;

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

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

  @Column({ type: 'varchar', length: 5, default: '4.0', nullable: false, name: 'cfdi_version' })
  cfdiVersion: string;

  @Column({
    type: 'enum',
    enum: CfdiVoucherType,
    default: CfdiVoucherType.INGRESO,
    nullable: false,
    name: 'voucher_type',
  })
  voucherType: CfdiVoucherType;

  // Issuer (Emisor)
  @Column({ type: 'varchar', length: 13, nullable: false, name: 'issuer_rfc' })
  issuerRfc: string;

  @Column({ type: 'varchar', length: 300, nullable: false, name: 'issuer_name' })
  issuerName: string;

  @Column({ type: 'varchar', length: 10, nullable: false, name: 'issuer_fiscal_regime' })
  issuerFiscalRegime: string;

  // Receiver (Receptor)
  @Column({ type: 'varchar', length: 13, nullable: false, name: 'receiver_rfc' })
  receiverRfc: string;

  @Column({ type: 'varchar', length: 300, nullable: false, name: 'receiver_name' })
  receiverName: string;

  @Column({ type: 'varchar', length: 10, nullable: true, name: 'receiver_fiscal_regime' })
  receiverFiscalRegime: string | null;

  @Column({ type: 'varchar', length: 5, nullable: true, name: 'receiver_zip_code' })
  receiverZipCode: string | null;

  @Column({ type: 'varchar', length: 3, nullable: true, name: 'receiver_tax_residence' })
  receiverTaxResidence: string | null;

  @Column({ type: 'varchar', length: 40, nullable: true, name: 'receiver_tax_id' })
  receiverTaxId: string | null;

  @Column({ type: 'varchar', length: 10, nullable: false, name: 'cfdi_use' })
  cfdiUse: string;

  // Amounts
  @Column({ type: 'decimal', precision: 18, scale: 6, default: 0, nullable: false, name: 'subtotal' })
  subtotal: number;

  @Column({ type: 'decimal', precision: 18, scale: 6, default: 0, nullable: true, name: 'discount' })
  discount: number | null;

  @Column({ type: 'decimal', precision: 18, scale: 6, default: 0, nullable: false, name: 'total' })
  total: number;

  @Column({ type: 'decimal', precision: 18, scale: 6, nullable: true, name: 'total_transferred_taxes' })
  totalTransferredTaxes: number | null;

  @Column({ type: 'decimal', precision: 18, scale: 6, nullable: true, name: 'total_withheld_taxes' })
  totalWithheldTaxes: number | null;

  @Column({ type: 'varchar', length: 3, default: 'MXN', nullable: false, name: 'currency' })
  currency: string;

  @Column({ type: 'decimal', precision: 10, scale: 6, default: 1, nullable: true, name: 'exchange_rate' })
  exchangeRate: number | null;

  // Exportation
  @Column({ type: 'varchar', length: 2, default: '01', nullable: true, name: 'exportation' })
  exportation: string | null;

  // Payment info
  @Column({ type: 'varchar', length: 10, nullable: false, name: 'payment_form' })
  paymentForm: string;

  @Column({ type: 'varchar', length: 10, nullable: false, name: 'payment_method' })
  paymentMethod: string;

  @Column({ type: 'varchar', length: 1000, nullable: true, name: 'payment_conditions' })
  paymentConditions: string | null;

  // Location
  @Column({ type: 'varchar', length: 5, nullable: false, name: 'expedition_place' })
  expeditionPlace: string;

  // Confirmation
  @Column({ type: 'varchar', length: 17, nullable: true, name: 'confirmation_code' })
  confirmationCode: string | null;

  // Related CFDI
  @Column({ type: 'varchar', length: 10, nullable: true, name: 'related_cfdi_type' })
  relatedCfdiType: string | null;

  // Global info (for global invoices)
  @Column({ type: 'varchar', length: 10, nullable: true, name: 'global_info_periodicity' })
  globalInfoPeriodicity: string | null;

  @Column({ type: 'varchar', length: 10, nullable: true, name: 'global_info_months' })
  globalInfoMonths: string | null;

  @Column({ type: 'varchar', length: 4, nullable: true, name: 'global_info_year' })
  globalInfoYear: string | null;

  // Status
  @Column({
    type: 'enum',
    enum: CfdiStatus,
    default: CfdiStatus.DRAFT,
    nullable: false,
  })
  status: CfdiStatus;

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

  @Column({ type: 'jsonb', nullable: true, name: 'error_details' })
  errorDetails: Record<string, any> | null;

  // Stamps
  @Column({ type: 'timestamptz', nullable: true, name: 'stamp_date' })
  stampDate: Date | null;

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

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

  @Column({ type: 'varchar', length: 20, nullable: true, name: 'sat_certificate_number' })
  satCertificateNumber: string | null;

  @Column({ type: 'varchar', length: 20, nullable: true, name: 'certificate_number' })
  certificateNumber: string | null;

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

  // XML Storage
  @Column({ type: 'text', nullable: true, name: 'xml_original' })
  xmlOriginal: string | null;

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

  // PDF
  @Column({ type: 'varchar', length: 500, nullable: true, name: 'pdf_url' })
  pdfUrl: string | null;

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

  // Cancellation
  @Column({ type: 'varchar', length: 50, nullable: true, name: 'cancellation_status' })
  cancellationStatus: string | null;

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

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

  // SAT Validation
  @Column({ type: 'timestamptz', nullable: true, name: 'last_sat_validation' })
  lastSatValidation: Date | null;

  @Column({ type: 'varchar', length: 50, nullable: true, name: 'sat_validation_status' })
  satValidationStatus: string | null;

  @Column({ type: 'jsonb', nullable: true, name: 'sat_validation_response' })
  satValidationResponse: Record<string, any> | null;

  // Relations
  @OneToMany(() => CfdiLog, (log) => log.cfdiInvoice, { cascade: true })
  logs: CfdiLog[];

  @OneToMany(() => CfdiCancellation, (cancellation) => cancellation.cfdiInvoice)
  cancellations: CfdiCancellation[];

  // Audit fields
  @Column({ type: 'timestamptz', nullable: true, name: 'stamped_at' })
  stampedAt: Date | null;

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

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

  @UpdateDateColumn({ name: 'updated_at', type: 'timestamptz', nullable: true })
  updatedAt: Date | null;

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

  @DeleteDateColumn({ name: 'deleted_at', type: 'timestamptz', nullable: true })
  deletedAt: Date | null;
}
