import mongoose, { Document, Model } from 'mongoose';

import { MODEL_NAMES } from './_models';
import { getUnitCostDifferenceFull } from '../queries/inventory/unit-cost-difference';
import { getInventoryTurnFull } from '../queries/inventory/turn';
import { getInventoryDifferenceFull } from '../queries/inventory/invoice-difference';
import { getInconsistentDataFull } from '../queries/inventory/inconsistent-data';
import { getInvoiceMovementFull } from '../queries/inventory/movement';
import { getExtensionFull } from '../queries/inventory/extension';
import { getReceivableDuplicatesFull } from '../queries/receivable/dublicates';
import { getAverageInvoiceFull } from '../queries/receivable/average-invoice-size';
import { getInvoiceDifferenceFull } from '../queries/receivable/invoice-difference';
import { getPartialPaidFull } from '../queries/receivable/partially-paid-restated';
import { getGroupedReceivablesFull } from '../queries/receivable/grouped-receivables';
import { getARTurnFull } from '../queries/receivable/ar-turn';

export type TQueryParams = {
  borrowerId?: mongoose.Types.ObjectId;
  bbcDateId?: mongoose.Types.ObjectId;
  startDate?: Date;
  endDate?: Date;
  extraParams?: { [key: string]: any };
};

export enum EQueriesGroups {
  INVENTORY = 'INVENTORY',
  RECEIVABLE = 'RECEIVABLE',
  OTHER = 'OTHER',
  CASH = 'CASH',
  SALES = 'SALES',
}

export enum EChartsInventory {
  BENFORD = 'BENFORD',
  EXPOSURES = 'EXPOSURES',
  EXPOSURES_CATEGORIES = 'EXPOSURES_CATEGORIES',
  AGING_PLOT = 'AGING_PLOT',
  AVERAGE_SKU_VALUES = 'AVERAGE_SKU_VALUES',
  UNIT_COST_DIFFERENCE = 'UNIT_COST_DIFFERENCE',
  INCONSISTENT_DATA = 'INCONSISTENT_DATA',
  INVENTORY_TURN = 'INVENTORY_TURN',
  INVOICE_DIFFERENCE = 'INVOICE_DIFFERENCE',
  MOVEMENT = 'MOVEMENT',
  EXTENSION = 'EXTENSION',
}

export enum EChartsReceivable {
  BENFORD = 'BENFORD',
  EXPOSURES = 'EXPOSURES',
  EXPOSURES_CUSTOMERS = 'EXPOSURES_CUSTOMERS',
  DUPLICATES = 'DUPLICATES',
  AVERAGE_INVOICE = 'AVERAGE_INVOICE',
  INVOICE_VALUE_PLOT = 'INVOICE_VALUE_PLOT',
  AGING_PLOT = 'AGING_PLOT',
  INVOICE_DIFFERENCE = 'INVOICE_DIFFERENCE',
  PARTIALLY_PAID_RESTATED = 'PARTIALLY_PAID_RESTATED',
  AR_TURN = 'AR_TURN',
  GROUP_CUSTOMERS = 'GROUP_CUSTOMERS',
}

export enum EChartsMisc {
  CONTRAS = 'CONTRAS',
}

export enum EChartsCash {
  TRANSACTIONS = 'TRANSACTIONS',
  DELUTION = 'DELUTION',
}

export enum EChartsSales {
  FOR_PERIOD = 'FOR_PERIOD',
}


export enum EFilterParams {
  NONE = 'NONE',
  BBC = 'BBC',
  PERIOD = 'PERIOD',
  CUSTOM = 'CUSTOM',
}

interface IQueryDetail {
  scheduled: boolean;
  queryAPI: string;
  queryFunction: ((params: TQueryParams) => unknown) | null;
  filterParams?: EFilterParams;
  sheetTitle?: string;
}

type TQueryGroups = {
  [EQueriesGroups.INVENTORY]: {
    [key in EChartsInventory]: IQueryDetail;
  };
  [EQueriesGroups.RECEIVABLE]: {
    [key in EChartsReceivable]: IQueryDetail;
  };
  [EQueriesGroups.OTHER]: {
    [key in EChartsMisc]: IQueryDetail;
  };
  [EQueriesGroups.CASH]: {
    [key in EChartsCash]: IQueryDetail;
  };
  [EQueriesGroups.SALES]: {
    [key in EChartsSales]: IQueryDetail;
  };
};

export const QUERY_GROUPS: TQueryGroups = {
  [EQueriesGroups.INVENTORY]: {
    [EChartsInventory.BENFORD]: { scheduled: false, queryAPI: 'benford', queryFunction: null },
    [EChartsInventory.INVOICE_DIFFERENCE]: {
      scheduled: true,
      queryAPI: 'invoice-difference',
      queryFunction: getInventoryDifferenceFull,
      filterParams: EFilterParams.BBC,
      sheetTitle: 'INV.New|Dropped SKUs',
    },
    [EChartsInventory.EXPOSURES]: { scheduled: false, queryAPI: 'exposures', queryFunction: null },
    [EChartsInventory.EXPOSURES_CATEGORIES]: {
      scheduled: false,
      queryAPI: 'exposures-categories',
      queryFunction: null,
    },
    [EChartsInventory.AVERAGE_SKU_VALUES]: { scheduled: false, queryAPI: 'average-sku-values', queryFunction: null },
    [EChartsInventory.AGING_PLOT]: { scheduled: false, queryAPI: 'aging-plot', queryFunction: null },
    [EChartsInventory.UNIT_COST_DIFFERENCE]: {
      scheduled: true,
      queryAPI: 'unit-cost-difference',
      queryFunction: getUnitCostDifferenceFull,
      filterParams: EFilterParams.NONE,
      sheetTitle: 'INV.Change in unit cost',
    },
    [EChartsInventory.INCONSISTENT_DATA]: {
      scheduled: true,
      queryAPI: 'inconsistent-data',
      queryFunction: getInconsistentDataFull,
      filterParams: EFilterParams.BBC,
      sheetTitle: 'INV.Inconsistent data',
    },
    [EChartsInventory.INVENTORY_TURN]: {
      scheduled: true,
      queryAPI: 'turn',
      queryFunction: getInventoryTurnFull,
      filterParams: EFilterParams.PERIOD,
      sheetTitle: 'INV.Inventory turn',
    },
    [EChartsInventory.MOVEMENT]: {
      scheduled: true,
      queryAPI: 'movement',
      queryFunction: getInvoiceMovementFull,
      filterParams: EFilterParams.BBC,
      sheetTitle: 'INV.Invoice Movement',
    },
    [EChartsInventory.EXTENSION]: {
      scheduled: true,
      queryAPI: 'extension',
      queryFunction: getExtensionFull,
      filterParams: EFilterParams.PERIOD,
      sheetTitle: 'INV.Extension',
    },
  },

  [EQueriesGroups.RECEIVABLE]: {
    [EChartsReceivable.BENFORD]: { scheduled: false, queryAPI: 'benford', queryFunction: null },
    [EChartsReceivable.EXPOSURES]: { scheduled: false, queryAPI: 'exposures', queryFunction: null },
    [EChartsReceivable.EXPOSURES_CUSTOMERS]: { scheduled: false, queryAPI: 'exposures-customers', queryFunction: null },
    [EChartsReceivable.DUPLICATES]: {
      scheduled: true,
      queryAPI: 'duplicates',
      queryFunction: getReceivableDuplicatesFull,
      filterParams: EFilterParams.BBC,
      sheetTitle: 'REC.Duplicates',
    },
    [EChartsReceivable.AVERAGE_INVOICE]: {
      scheduled: true,
      queryAPI: 'average-invoice',
      queryFunction: getAverageInvoiceFull,
      filterParams: EFilterParams.NONE,
      sheetTitle: 'REC.Average invoice',
    },
    [EChartsReceivable.INVOICE_VALUE_PLOT]: { scheduled: false, queryAPI: 'average-sku-values', queryFunction: null },
    [EChartsReceivable.AGING_PLOT]: { scheduled: false, queryAPI: 'aging-plot', queryFunction: null },
    [EChartsReceivable.INVOICE_DIFFERENCE]: {
      scheduled: true,
      queryAPI: 'invoice-difference',
      queryFunction: getInvoiceDifferenceFull,
      filterParams: EFilterParams.BBC,
      sheetTitle: 'REC.AR movement report',
    },
    [EChartsReceivable.PARTIALLY_PAID_RESTATED]: {
      scheduled: true,
      queryAPI: 'partially-paid-restated',
      queryFunction: getPartialPaidFull,
      filterParams: EFilterParams.PERIOD,
      sheetTitle: 'REC.Partially paid & restated',
    },
    [EChartsReceivable.AR_TURN]: {
      scheduled: true,
      queryAPI: 'ar-turn',
      queryFunction: getARTurnFull,
      filterParams: EFilterParams.CUSTOM,
      sheetTitle: 'REC.AR Turn',
    },
    [EChartsReceivable.GROUP_CUSTOMERS]: {
      scheduled: true,
      queryAPI: 'grouped-receivables',
      queryFunction: getGroupedReceivablesFull,
      filterParams: EFilterParams.BBC,
      sheetTitle: 'REC.Detailed grouped receivables',
    },
  },

  [EQueriesGroups.OTHER]: {
    [EChartsMisc.CONTRAS]: { scheduled: false, queryAPI: 'contras', queryFunction: null },
  },

  [EQueriesGroups.CASH]: {
    [EChartsCash.TRANSACTIONS]: { scheduled: false, queryAPI: 'transactions', queryFunction: null },
    [EChartsCash.DELUTION]: { scheduled: false, queryAPI: 'delution', queryFunction: null },
  },

  [EQueriesGroups.SALES]: {
    [EChartsSales.FOR_PERIOD]: { scheduled: false, queryAPI: 'sales-for-period', queryFunction: null },
  }
};


export interface IQueryResult {
  query: string;
  filter: Object;
  userId?: string;
  result: Object;
}

export interface IQueryResultDoc extends IQueryResult, Document {
}

type TQueryResultModel = Model<IQueryResult, {}, {}>;

export const QueryResultSchema = new mongoose.Schema<IQueryResult, TQueryResultModel>(
  {
    query: {
      type: String,
      required: true,
    },
    filter: mongoose.Schema.Types.Mixed,
    userId: {
      type: String,
      required: false,
    },
    result: mongoose.Schema.Types.Mixed,
  },
  { timestamps: true },
);

export const QueryResult = mongoose.model<IQueryResult, TQueryResultModel>(MODEL_NAMES.queryResult, QueryResultSchema);
