import { createElement, lazy } from 'react'

const InvoiceInfo = lazy(
  () => import('../../components/Dashboard/Finance/Invoices/InvoiceInfo')
)
const PostInvoice = lazy(
  () => import('../../components/Dashboard/Finance/Invoices/PostInvoice')
)
const AcknowledgeInvoice = lazy(
  () => import('../../components/Dashboard/Finance/Invoices/AcknowledgeInvoice')
)
const NewPayment = lazy(
  () => import('../../components/Dashboard/Finance/Payments/NewPayment')
)
import InvoiceIcon from '../../components/Icons/InvoiceIcon'
import InfoCircleIcon from '../../components/Icons/InfoCircleIcon'
import CheckIcon from '../../components/Icons/CheckIcon'
import EditIcon from '../../components/Icons/EditIcon'
import XMarkIcon from '../../components/Icons/XMarkIcon'
import BinIcon from '../../components/Icons/BinIcon'
import PlusIcon from '../../components/Icons/PlusIcon'

export const Invoice = {
  name: 'invoice',
  label: 'Invoice',
  labelPlural: 'Invoices',
  url: '/dashboard/finance/invoices',
  prefix: 'INV',
  icon: InvoiceIcon,
  actions: [
    {
      name: 'info',
      type: 'page',
      pageName: 'info',
      label: 'Info',
      default: true,
      row: true,
      icon: InfoCircleIcon
    },
    {
      name: 'edit',
      type: 'page',
      pageName: 'info',
      label: 'Edit',
      row: true,
      icon: EditIcon,
      visible: (objectData) => {
        return !(objectData?._isEditing && objectData?._isEditing == true)
      },
      disabled: (objectData) => {
        return objectData?.state?.type != 'draft'
      }
    },
    {
      name: 'cancelEdit',
      label: 'Cancel Edits',
      type: 'page',
      pageName: 'info',
      icon: XMarkIcon,
      visible: (objectData) => {
        return objectData?._isEditing && objectData?._isEditing == true
      }
    },
    {
      name: 'finishEdit',
      label: 'Save Edits',
      type: 'page',
      pageName: 'info',
      icon: CheckIcon,
      visible: (objectData) => {
        return objectData?._isEditing && objectData?._isEditing == true
      }
    },
    {
      name: 'delete',
      type: 'page',
      pageName: 'info',
      label: 'Delete',
      icon: BinIcon,
      danger: true,
      visible: (objectData) => {
        return !(objectData?._isEditing && objectData?._isEditing == true)
      },
      disabled: (objectData) => {
        return objectData?.state?.type != 'draft'
      }
    },
    { type: 'divider' },
    {
      name: 'newPayment',
      type: 'modal',
      modalWidth: 700,
      label: 'New Payment',
      icon: PlusIcon,
      disabled: (objectData) => {
        const allowedStates = ['acknowledged', 'partiallyPaid', 'overdue']
        return !allowedStates.includes(objectData?.state?.type)
      },
      content: (objectData, { onOk } = {}) => {
        return createElement(NewPayment, {
          defaultValues: {
            invoice: objectData,
            amount: objectData?.grandTotalAmount
          },
          onOk,
          reset: true
        })
      }
    },
    { type: 'divider' },
    {
      name: 'post',
      type: 'modal',
      modalWidth: 520,
      label: 'Post',
      icon: CheckIcon,
      visible: (objectData) => {
        return objectData?.state?.type == 'draft'
      },
      content: (objectData, { onOk } = {}) => {
        return createElement(PostInvoice, { objectData, onOk })
      }
    },
    {
      name: 'acknowledge',
      type: 'modal',
      modalWidth: 520,
      label: 'Acknowledge',
      icon: CheckIcon,
      visible: (objectData) => {
        return objectData?.state?.type == 'sent'
      },
      content: (objectData, { onOk } = {}) => {
        return createElement(AcknowledgeInvoice, { objectData, onOk })
      }
    },
    {
      name: 'cancel',
      type: 'page',
      pageName: 'info',
      label: 'Cancel',
      icon: XMarkIcon,
      danger: true,
      disabled: (objectData) => {
        const allowedStates = [
          'acknowledged',
          'partiallyPaid',
          'overdue',
          'sent'
        ]
        return !allowedStates.includes(objectData?.state?.type)
      },
      visible: (objectData) => {
        return objectData?.state?.type != 'draft'
      }
    }
  ],
  pages: [
    {
      name: 'info',
      content: () => createElement(InvoiceInfo)
    }
  ],
  group: ['orderType'],
  filters: [
    'vendor',
    'client',
    'state',
    'vendor._id',
    'client._id',
    'order',
    'order._id',
    'orderType',
    'createdAt',
    'updatedAt',
    '_reference'
  ],
  sorters: ['createdAt', 'state', 'updatedAt', 'invoiceDate', 'dueDate'],
  columns: [
    '_reference',
    'state',
    'orderType',
    'to',
    'from',
    'invoiceDate',
    'dueDate',
    'totalAmount',
    'totalAmountWithTax',
    'totalTaxAmount',
    'shippingAmount',
    'shippingAmountWithTax',
    'grandTotalAmount',
    'createdAt',
    'updatedAt'
  ],
  properties: [
    {
      name: '_id',
      label: 'ID',
      type: 'id',
      columnFixed: 'left',
      objectType: 'invoice',
      columnWidth: 140,
      showCopy: true
    },
    {
      name: 'createdAt',
      label: 'Created At',
      type: 'dateTime',
      readOnly: true,
      columnWidth: 175
    },
    {
      name: '_reference',
      label: 'Reference',
      type: 'reference',
      columnFixed: 'left',
      required: true,
      objectType: 'invoice',
      showCopy: true,
      readOnly: true,
      columnWidth: 180
    },
    {
      name: 'updatedAt',
      label: 'Updated At',
      type: 'dateTime',
      readOnly: true,
      columnWidth: 175
    },
    {
      name: 'state',
      label: 'State',
      type: 'state',
      readOnly: true,
      columnWidth: 260
    },
    {
      name: 'issuedAt',
      label: 'Issued At',
      type: 'dateTime',
      readOnly: false,
      required: true,
      columnWidth: 175
    },
    {
      name: 'orderType',
      label: 'Order Type',
      type: 'objectType',
      masterFilter: ['purchaseOrder', 'salesOrder'],
      required: true,
      columnWidth: 150
    },
    {
      name: 'dueAt',
      label: 'Due At',
      type: 'dateTime',
      required: true,
      columnWidth: 175
    },
    {
      name: 'order',
      label: 'Order',
      type: 'object',
      objectType: (objectData) => {
        return objectData?.orderType
      },
      required: true,
      showHyperlink: true,
      columnWidth: 200
    },
    {
      name: 'postedAt',
      label: 'Posted At',
      type: 'dateTime',
      readOnly: true,
      columnWidth: 175
    },
    {
      name: 'fromType',
      label: 'From Type',
      type: 'objectType',
      value: (objectData) => {
        return objectData?.orderType == 'purchaseOrder'
          ? 'vendor'
          : objectData?.fromType
      },
      masterFilter: ['client', 'vendor'],
      readOnly: (objectData) => {
        return objectData?.orderType == 'purchaseOrder' ? true : false
      },
      columnWidth: 150,
      required: true
    },
    {
      name: 'acknowledgedAt',
      label: 'Acknowledged At',
      type: 'dateTime',
      readOnly: true,
      columnWidth: 175
    },
    {
      name: 'from',
      label: 'From',
      required: true,
      type: 'object',
      objectType: (objectData) => {
        return objectData?.fromType
      },
      showHyperlink: true,
      readOnly: (objectData) => {
        return objectData?.orderType == 'purchaseOrder' ? true : false
      },
      columnWidth: 200,
      value: (objectData) => {
        if (objectData?.orderType == 'purchaseOrder') {
          return objectData?.order?.vendor
        } else {
          return objectData?.from
        }
      }
    },

    {
      name: 'cancelledAt',
      label: 'Cancelled At',
      type: 'dateTime',
      readOnly: true,
      columnWidth: 175
    },

    {
      name: 'toType',
      label: 'To Type',
      type: 'objectType',
      masterFilter: ['vendor', 'client'],
      value: (objectData) => {
        return objectData?.orderType == 'salesOrder'
          ? 'client'
          : objectData?.toType
      },
      readOnly: (objectData) => {
        return objectData?.orderType == 'salesOrder' ? true : false
      },
      columnWidth: 150,
      required: true
    },

    {
      name: 'paidAt',
      label: 'Paid At',
      type: 'dateTime',
      readOnly: true,
      columnWidth: 175
    },

    {
      name: 'to',
      label: 'To',
      required: true,
      type: 'object',
      objectType: (objectData) => {
        return objectData?.toType
      },
      showHyperlink: true,
      readOnly: (objectData) => {
        return objectData?.orderType == 'salesOrder' ? true : false
      },
      columnWidth: 200,
      value: (objectData) => {
        if (objectData?.orderType == 'salesOrder') {
          return objectData?.order?.client
        } else {
          return objectData?.to
        }
      }
    },

    {
      name: 'totalTaxAmount',
      label: 'Total Tax Amount',
      type: 'number',
      prefix: '£',
      roundNumber: 2,
      readOnly: true,
      columnWidth: 175
    },

    {
      name: 'totalAmountWithTax',
      label: 'Total Amount w/ Tax',
      type: 'number',
      prefix: '£',
      readOnly: true,
      columnWidth: 175,
      roundNumber: 2
    },
    {
      name: 'shippingAmount',
      label: 'Shipping Amount',
      type: 'number',
      prefix: '£',
      roundNumber: 2,
      readOnly: true,
      columnWidth: 150
    },
    {
      name: 'shippingAmountWithTax',
      label: 'Shipping Amount w/ Tax',
      type: 'number',
      prefix: '£',
      readOnly: true,
      roundNumber: 2,
      columnWidth: 200
    },
    {
      name: 'totalAmount',
      label: 'Total Amount',
      type: 'number',
      prefix: '£',
      roundNumber: 2,
      readOnly: true,
      columnWidth: 150
    },
    {
      name: 'grandTotalAmount',
      label: 'Grand Total Amount',
      type: 'number',
      prefix: '£',
      roundNumber: 2,
      columnWidth: 175,
      readOnly: true
    },
    {
      name: 'invoiceOrderItems',
      label: 'Invoice Order Items',
      type: 'objectChildren',
      objectType: 'orderItem',
      properties: [
        {
          name: 'orderItem',
          label: 'Order Item',
          type: 'object',
          objectType: 'orderItem',
          required: true,
          columnWidth: 300,
          showHyperlink: true,
          masterFilter: (objectData, parentData) => {
            return {
              orderType: parentData?.orderType,
              order: parentData?.order?._id
            }
          }
        },
        {
          name: 'invoiceQuantity',
          label: 'Quantity',
          type: 'number',
          required: true,
          columnWidth: 175
        },
        {
          name: 'invoiceAmount',
          label: 'Invoice Amount',
          type: 'number',
          prefix: '£',
          roundNumber: 2,
          required: true,
          columnWidth: 150
        },
        {
          name: 'taxRate',
          label: 'Tax Rate',
          type: 'object',
          objectType: 'taxRate',
          required: false,
          showHyperlink: true,
          columnWidth: 200
        },
        {
          name: 'invoiceAmountWithTax',
          label: 'Invoice Amount w/ Tax',
          type: 'number',
          prefix: '£',
          roundNumber: 2,
          required: true,
          readOnly: true,
          columnWidth: 200,
          value: (objectData) => {
            const invoiceAmount = objectData?.invoiceAmount || 0
            if (!invoiceAmount) return 0
            if (objectData?.taxRate?.rateType == 'percentage') {
              return (
                (invoiceAmount * (1 + objectData?.taxRate?.rate / 100)).toFixed(
                  2
                ) || 0
              )
            } else if (objectData?.taxRate?.rateType == 'amount') {
              return (invoiceAmount + objectData?.taxRate?.rate).toFixed(2) || 0
            }
            return invoiceAmount
          }
        }
      ],
      rollups: [
        {
          name: 'totalQuantity',
          label: 'Total Quantity',
          type: 'number',
          property: 'invoiceQuantity',
          value: (objectData) => {
            return objectData?.invoiceOrderItems?.reduce(
              (acc, item) => acc + (item.invoiceQuantity || 0),
              0
            )
          }
        },
        {
          name: 'totalAmount',
          label: 'Total Amount',
          type: 'number',
          property: 'invoiceAmount',
          prefix: '£',
          fixedNumber: 2,
          value: (objectData) => {
            return objectData?.invoiceOrderItems
              ?.reduce(
                (acc, item) =>
                  acc + (Number.parseFloat(item.invoiceAmount) || 0),
                0
              )
              .toFixed(2)
          }
        },
        {
          name: 'totalAmountWithTax',
          label: 'Total Amount w/ Tax',
          type: 'number',
          property: 'invoiceAmountWithTax',
          prefix: '£',
          fixedNumber: 2,
          value: (objectData) => {
            return objectData?.invoiceOrderItems
              ?.reduce(
                (acc, item) =>
                  acc + (Number.parseFloat(item.invoiceAmountWithTax) || 0),
                0
              )
              .toFixed(2)
          }
        }
      ]
    },
    {
      name: 'invoiceShipments',
      label: 'Invoice Shipments',
      type: 'objectChildren',
      objectType: 'shipment',
      properties: [
        {
          name: 'shipment',
          label: 'Shipment',
          type: 'object',
          objectType: 'shipment',
          required: true,
          columnWidth: 300,
          showHyperlink: true,
          masterFilter: (objectData, parentData) => {
            return {
              orderType: parentData?.orderType,
              order: parentData?.order?._id
            }
          }
        },
        {
          name: 'invoiceAmount',
          label: 'Invoice Amount',
          type: 'number',
          prefix: '£',
          roundNumber: 2,
          columnWidth: 175,
          required: true
        },
        {
          name: 'taxRate',
          label: 'Tax Rate',
          type: 'object',
          objectType: 'taxRate',
          required: false,
          showHyperlink: true,
          columnWidth: 200
        },
        {
          name: 'invoiceAmountWithTax',
          label: 'Invoice Amount w/ Tax',
          type: 'number',
          prefix: '£',
          roundNumber: 2,
          required: true,
          readOnly: true,
          columnWidth: 200,
          value: (objectData) => {
            const invoiceAmount = objectData?.invoiceAmount || 0
            if (!invoiceAmount) return 0
            if (objectData?.taxRate?.rateType == 'percentage') {
              return (
                (invoiceAmount * (1 + objectData?.taxRate?.rate / 100)).toFixed(
                  2
                ) || 0
              )
            } else if (objectData?.taxRate?.rateType == 'amount') {
              return (invoiceAmount + objectData?.taxRate?.rate).toFixed(2) || 0
            }
            return invoiceAmount
          }
        }
      ],
      rollups: [
        {
          name: 'totalAmount',
          label: 'Total Amount',
          type: 'number',
          property: 'invoiceAmount',
          prefix: '£',
          roundNumber: 2,
          value: (objectData) => {
            return objectData?.invoiceShipments
              ?.reduce(
                (acc, shipment) => acc + (shipment.invoiceAmount || 0),
                0
              )
              .toFixed(2)
          }
        },
        {
          name: 'totalAmountWithTax',
          label: 'Total Amount w/ Tax',
          type: 'number',
          property: 'invoiceAmountWithTax',
          prefix: '£',
          roundNumber: 2,
          value: (objectData) => {
            return objectData?.invoiceShipments
              ?.reduce(
                (acc, shipment) =>
                  acc + (Number.parseFloat(shipment.invoiceAmountWithTax) || 0),
                0
              )
              .toFixed(2)
          }
        }
      ]
    }
  ],
  stats: [
    {
      name: 'draft.draftCount.count',
      label: 'Draft',
      type: 'number',
      color: 'default'
    },
    {
      name: 'draft.draftGrandTotalAmount.sum',
      label: 'Draft Grand Total Amount',
      type: 'number',
      prefix: '£',
      roundNumber: 2,
      color: 'default'
    },
    {
      name: 'sent.sentCount.count',
      label: 'Sent',
      type: 'number',
      color: 'cyan'
    },
    {
      name: 'acknowledged.acknowledgedCount.count',
      label: 'Acknowledged',
      type: 'number',
      color: 'purple'
    },
    {
      name: 'due.dueCount.count',
      label: 'Due',
      type: 'number',
      color: 'warning',
      sum: [
        'sent.sentCount.count',
        'partiallyPaid.partiallyPaidCount.count',
        'overdue.overdueCount.count',
        'acknowledged.acknowledgedCount.count'
      ]
    },
    {
      name: 'due.dueGrandTotalAmount.sum',
      label: 'Due Grand Total Amount',
      type: 'number',
      prefix: '£',
      roundNumber: 2,
      color: 'warning',
      sum: [
        'sent.sentGrandTotalAmount.sum',
        'partiallyPaid.partiallyPaidGrandTotalAmount.sum',
        'overdue.overdueGrandTotalAmount.sum',
        'acknowledged.acknowledgedGrandTotalAmount.sum'
      ]
    },
    {
      name: 'partiallyPaid.partiallyPaidCount.count',
      label: 'Partially Paid',
      type: 'number',
      color: 'processing'
    },
    {
      name: 'overdue.overdueCount.count',
      label: 'Overdue',
      type: 'number',
      color: 'error'
    },
    {
      name: 'overdue.overdueGrandTotalAmount.sum',
      label: 'Overdue Grand Total Amount',
      type: 'number',
      prefix: '£',
      roundNumber: 2,
      color: 'error'
    }
  ]
}
