import mongoose, { Document } from 'mongoose';

import { IReceivableAvailabilityItem, IReceivableAvailabilityItemView } from './ReceivableAvailabilityItem.model';
import { IUser } from '../interfaces/auth-user.interface';
import { MODEL_NAMES } from './_models';
import { SummaryMultipliers } from './ReceivableAvailabilityManualSummary.model';

const mongooseLeanId = require('../plugins/id.plugin');

export enum ELimitSettings {
  EXCLUDED_CUSTOMERS = 'excludedCustomers',
  PERMITTED_CONCENTRATION = 'permittedConcentration',
  PERMITTED_EXTENDED_AR_DAYS = 'permittedExtendedARDays',
  INSURED_CUSTOMERS = 'insuredCustomers',
}

export type IAvailabilitySettingsLimits = {
  [key in ELimitSettings]: IAvailabilityLimits[];
}

export interface IAvailabilityLimits {
  customer: string;
  limit: number;
}

export interface IAvailabilitySettings extends IAvailabilitySettingsLimits {
  standardARDays: number;
  customerConcentrationLimit: number;
  crossAgeLimit: number;
  contraProvision: number;
  paidDays: number;
  insuredARAdvanceRate: number;
  uninsuredARAdvanceRate: number;
  excludeFromTotal: boolean;
  waiveInsuredCustomers: boolean;
}

export interface IAvailabilitySummary {
  invoiceAmount: number;
  creditNotes: number;
  excludedCustomerDeduction: number;
  grossAR: number;
  permittedOver: number;
  preliminaryEligibleBalance: number;
  creditNotesNegative: number;
  deduction: number;
  partiallyPaidDeduction: number;
  contraDeduction: number;
  crossAgeDeduction: number;
  waivedDeduction: number;
  balanceAfterCrossAge: number;
  finalResult: number;
  insuredComponent: number;
  uninsuredComponent: number;
  insuredAvailability: number;
  uninsuredAvailability: number;
  ARReserves: number;
  ARAvailability: number;
}

export interface IReceivableManualSummary {
  summary: IAvailabilitySummary;
  multipliers: SummaryMultipliers;
}

export interface IReceivableAvailability {
  borrowerId: mongoose.Types.ObjectId;
  bbcDateId: mongoose.Types.ObjectId;
  userCalculatedId: string;
  calculatedAt: Date;
  actual: boolean;
  settings?: IAvailabilitySettings;
  summary?: IAvailabilitySummary;
  items: IReceivableAvailabilityItem[];
  totalItems: number;
  useManualInputs: boolean;
}

export interface IReceivableAvailabilityDoc extends IReceivableAvailability, Document {
}

export interface IReceivableAvailabilityView extends IReceivableAvailabilityDoc {
  items: IReceivableAvailabilityItemView[];
  uniqueCustomers: string[];
  totalItems: number;
  userCalculated?: IUser;
}

export const summarySchemeDesc = {
  invoiceAmount: {
    type: Number,
    required: false,
  },
  creditNotes: {
    type: Number,
    required: false,
  },
  excludedCustomerDeduction: {
    type: Number,
    required: false,
  },
  grossAR: {
    type: Number,
    required: false,
  },
  permittedOver: {
    type: Number,
    required: false,
  },
  preliminaryEligibleBalance: {
    type: Number,
    required: false,
  },
  creditNotesNegative: {
    type: Number,
    required: false,
  },
  deduction: {
    type: Number,
    required: false,
  },
  partiallyPaidDeduction: {
    type: Number,
    required: false,
  },
  contraDeduction: {
    type: Number,
    required: false,
  },
  crossAgeDeduction: {
    type: Number,
    required: false,
  },
  waivedDeduction: {
    type: Number,
    required: false,
  },
  balanceAfterCrossAge: {
    type: Number,
    required: false,
  },
  finalResult: {
    type: Number,
    required: false,
  },
  insuredComponent: {
    type: Number,
    required: false,
  },
  uninsuredComponent: {
    type: Number,
    required: false,
  },
  insuredAvailability: {
    type: Number,
    required: false,
  },
  uninsuredAvailability: {
    type: Number,
    required: false,
  },
  ARReserves: {
    type: Number,
    required: false,
  },
  ARAvailability: {
    type: Number,
    required: false,
  },
}

export const AvailabilitySchema = new mongoose.Schema(
  {
    borrowerId: {
      type: mongoose.Schema.Types.ObjectId,
      ref: MODEL_NAMES.borrowers,
      required: true,
    },
    bbcDateId: {
      type: mongoose.Schema.Types.ObjectId,
      ref: MODEL_NAMES.BBCDates,
      required: true,
    },
    userCalculatedId: {
      type: String,
      required: false,
    },
    calculatedAt: {
      type: Date,
      required: false,
    },
    actual: {
      type: Boolean,
      required: false,
      default: false,
    },
    useManualInputs: {
      type: Boolean,
      default: false,
    },
    settings: {
      standardARDays: {
        type: Number,
        required: false,
      },
      customerConcentrationLimit: {
        type: Number,
        required: false,
      },
      crossAgeLimit: {
        type: Number,
        required: false,
      },
      contraProvision: {
        type: Number,
        required: false,
      },
      paidDays: {
        type: Number,
        required: false,
      },
      insuredARAdvanceRate: {
        type: Number,
        required: false,
      },
      uninsuredARAdvanceRate: {
        type: Number,
        required: false,
      },
      excludeFromTotal: {
        type: Boolean,
        required: false,
        default: true,
      },
      waiveInsuredCustomers: {
        type: Boolean,
        required: false,
        default: true,
      },
      excludedCustomers: [
        {
          customer: {
            type: String,
            required: false,
          },
          limit: {
            type: Number,
            required: false,
          }
        },
      ],
      insuredCustomers: [
        {
          customer: {
            type: String,
            required: false,
          },
          limit: {
            type: Number,
            required: false,
          }
        },
      ],
      permittedConcentration: [
        {
          customer: {
            type: String,
            required: false,
          },
          limit: {
            type: Number,
            required: false,
          }
        },
      ],
      permittedExtendedARDays: [
        {
          customer: {
            type: String,
            required: false,
          },
          limit: {
            type: Number,
            required: false,
          }
        },
      ],
    },
    summary: summarySchemeDesc,
    __v: { type: Number, select: false },
  },
  { timestamps: true }
);

AvailabilitySchema.plugin(mongooseLeanId);

export const ReceivableAvailabilityModel: mongoose.Model<IReceivableAvailabilityDoc> = mongoose.model<IReceivableAvailabilityDoc>(MODEL_NAMES.ARAvailabilities, AvailabilitySchema);
