import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
import { Document } from 'mongoose';
import { BaseEntity } from '../../common/entities/base.entity';

export type InvoiceDocument = Invoice & Document;

@Schema({ timestamps: true })
export class Invoice extends BaseEntity {
    // Uniqueness enforced by the explicit InvoiceSchema.index() call below —
    // duplicating `unique: true` here would register two identical indexes and
    // Mongoose logs a "Duplicate schema index" warning on startup.
    @Prop({ required: true, trim: true })
    invoiceNumber: string;

    @Prop({ trim: true })
    paymentId?: string;

    // Auto-generated (RCPT-YYYY-NNNNNN) when the invoice first transitions to a
    // paid/partial state. Mirrors the fee-side receipt semantics so every paid
    // invoice has a distinct receipt identifier even when it's a manual invoice
    // with no linked FeeAssignment.
    @Prop({ trim: true })
    receiptNumber?: string;

    // Auto-generated (TXN-YYYY-NNNNNN) at paid-transition unless the admin
    // supplies a real bank/UPI/cheque reference via the create/update DTO.
    @Prop({ trim: true, maxlength: 200 })
    transactionId?: string;

    @Prop({ trim: true })
    feeAssignmentId?: string;

    @Prop({ trim: true })
    feeName?: string;

    @Prop({ trim: true })
    installment?: string;

    @Prop({ required: true })
    studentId: string;

    @Prop({ required: true, trim: true })
    studentName: string;

    @Prop({ required: true, trim: true })
    studentUniqueId: string;

    @Prop({ required: true })
    classId: string;

    @Prop({ required: true, trim: true })
    className: string;

    @Prop({ required: true })
    academicYearId: string;

    @Prop({ required: true, min: 0 })
    amount: number;

    @Prop({ default: 0, min: 0 })
    fineAmount: number;

    @Prop({ default: 0, min: 0 })
    totalPaid: number;

    @Prop({ default: 0, min: 0 })
    balance: number;

    @Prop({ required: true, enum: ['pending', 'paid', 'partial'], default: 'pending' })
    status: 'pending' | 'paid' | 'partial';

    @Prop({ enum: ['cash', 'upi', 'cheque', 'bank_transfer', 'online'] })
    paymentMode?: 'cash' | 'upi' | 'cheque' | 'bank_transfer' | 'online';

    @Prop({ type: Date, default: () => new Date() })
    date: Date;

    @Prop({ required: true, trim: true })
    generatedBy: string;

    @Prop({ default: true })
    isActive: boolean;

    @Prop({ trim: true, maxlength: 2000 })
    notes?: string;
}

export const InvoiceSchema = SchemaFactory.createForClass(Invoice);

// Indexes
InvoiceSchema.index({ invoiceNumber: 1 }, { unique: true });
InvoiceSchema.index({ paymentId: 1 }, { unique: true, sparse: true });
InvoiceSchema.index({ receiptNumber: 1 }, { unique: true, sparse: true });
InvoiceSchema.index({ transactionId: 1 }, { unique: true, sparse: true });
InvoiceSchema.index({ feeAssignmentId: 1 }, { unique: true, sparse: true });
InvoiceSchema.index({ studentId: 1, academicYearId: 1 });
InvoiceSchema.index({ classId: 1, academicYearId: 1 });
InvoiceSchema.index({ status: 1, date: -1 });
InvoiceSchema.index({ academicYearId: 1 });

// Virtual id
InvoiceSchema.virtual('id').get(function (this: any) {
    return this._id?.toString?.() ?? String(this._id);
});

const jsonOpts = {
    versionKey: false,
    virtuals: true,
};
InvoiceSchema.set('toJSON', jsonOpts as any);
InvoiceSchema.set('toObject', jsonOpts as any);
