import { t } from '@lingui/core/macro';
import { Alert, Table, Text } from '@mantine/core';
import {
  IconAddressBook,
  IconCalendar,
  IconCircleCheck,
  IconCircleX,
  IconCoins,
  IconUser,
  IconUsers
} from '@tabler/icons-react';
import { useEffect, useMemo, useState } from 'react';

import { ApiEndpoints } from '@lib/enums/ApiEndpoints';
import { ModelType } from '@lib/enums/ModelType';
import RemoveRowButton from '../components/buttons/RemoveRowButton';
import { StandaloneField } from '../components/forms/StandaloneField';

import { ProgressBar } from '@lib/components/ProgressBar';
import { apiUrl } from '@lib/functions/Api';
import { toNumber } from '@lib/functions/Conversion';
import type {
  ApiFormAdjustFilterType,
  ApiFormFieldSet,
  ApiFormFieldType
} from '@lib/types/Forms';
import dayjs from 'dayjs';
import {
  TableFieldQuantityInput,
  type TableFieldRowProps
} from '../components/forms/fields/TableField';
import useBackgroundTask from '../hooks/UseBackgroundTask';
import { useCreateApiFormModal, useEditApiFormModal } from '../hooks/UseForm';
import { useGlobalSettingsState } from '../states/SettingsStates';
import { useUserState } from '../states/UserState';
import { RenderPartColumn } from '../tables/ColumnRenderers';
import { ProjectCodeField, TagsField } from './CommonFields';

export function useSalesOrderFields({
  duplicateOrderId
}: {
  duplicateOrderId?: number;
}): ApiFormFieldSet {
  const globalSettings = useGlobalSettingsState();

  return useMemo(() => {
    const fields: ApiFormFieldSet = {
      reference: {},
      description: {},
      customer: {
        disabled: duplicateOrderId != undefined,
        filters: {
          is_customer: true,
          active: true
        },
        addCreateFields: {
          name: {},
          description: {},
          is_customer: { value: true, hidden: true }
        }
      },
      customer_reference: {},
      project_code: ProjectCodeField(),
      order_currency: {},
      start_date: {
        icon: <IconCalendar />
      },
      target_date: {
        icon: <IconCalendar />
      },
      tags: TagsField({}),
      link: {},
      contact: {
        icon: <IconUser />,
        adjustFilters: (value: ApiFormAdjustFilterType) => {
          return {
            ...value.filters,
            company: value.data.customer
          };
        }
      },
      address: {
        icon: <IconAddressBook />,
        adjustFilters: (value: ApiFormAdjustFilterType) => {
          return {
            ...value.filters,
            company: value.data.customer
          };
        }
      },
      responsible: {
        icon: <IconUsers />
      }
    };

    // Order duplication fields
    if (!!duplicateOrderId) {
      fields.duplicate = {
        children: {
          original: {
            hidden: true,
            value: duplicateOrderId
          },
          copy_lines: {},
          copy_extra_lines: {},
          copy_parameters: {}
        }
      };
    }

    if (!globalSettings.isSet('PROJECT_CODES_ENABLED', true)) {
      delete fields.project_code;
    }

    return fields;
  }, [duplicateOrderId, globalSettings]);
}

export function useSalesOrderLineItemFields({
  customerId,
  orderId,
  create,
  currency
}: {
  customerId?: number;
  orderId?: number;
  create?: boolean;
  currency?: string;
}): ApiFormFieldSet {
  const [salePrice, setSalePrice] = useState<string | undefined>(undefined);
  const [partCurrency, setPartCurrency] = useState<string>(currency ?? '');
  const [part, setPart] = useState<any>({});
  const [quantity, setQuantity] = useState<string>('1');

  // Update suggested sale price when part, quantity, or part currency changes
  useEffect(() => {
    // Only attempt to set sale price for new line items
    if (!create) return;

    const qty = toNumber(quantity, null);

    if (qty == null || qty <= 0) {
      setSalePrice(undefined);
      return;
    }

    if (!part || !part.price_breaks || part.price_breaks.length === 0) {
      setSalePrice(undefined);
      return;
    }

    const applicablePriceBreaks = part?.price_breaks
      ?.filter(
        (pb: any) => pb.price_currency == partCurrency && qty >= pb.quantity
      )
      .sort((a: any, b: any) => b.quantity - a.quantity);

    if (applicablePriceBreaks.length) {
      setSalePrice(applicablePriceBreaks[0].price);
    } else {
      setSalePrice(undefined);
    }
  }, [part, quantity, partCurrency, create]);

  return useMemo(() => {
    const fields: ApiFormFieldSet = {
      order: {
        filters: {
          customer_detail: true
        },
        disabled: true,
        value: create ? orderId : undefined
      },
      part: {
        filters: {
          active: true,
          salable: true,
          price_breaks: true
        },
        onValueChange: (_: any, record?: any) => setPart(record)
      },
      line: {},
      reference: {},
      quantity: {
        onValueChange: (value) => {
          setQuantity(value);
        }
      },
      sale_price: {
        placeholder: salePrice,
        placeholderAutofill: true,
        placeholderWarningCompare: salePrice,
        placeholderWarning: t`Price based on part and quantity differs${salePrice ? `; suggested: (${salePrice})` : '.'}`
      },
      sale_price_currency: {
        icon: <IconCoins />,
        value: partCurrency,
        onValueChange: setPartCurrency
      },
      project_code: ProjectCodeField(),
      target_date: {},
      notes: {},
      link: {}
    };

    return fields;
  }, [salePrice, partCurrency, orderId, create]);
}

export function useCheckShipmentForm({
  shipmentId,
  onSuccess
}: {
  shipmentId: number;
  onSuccess: (response: any) => void;
}) {
  const user = useUserState();

  return useEditApiFormModal({
    url: ApiEndpoints.sales_order_shipment_list,
    pk: shipmentId,
    title: t`Check Shipment`,
    preFormContent: (
      <Alert color='green' icon={<IconCircleCheck />} title={t`Check Shipment`}>
        <Text>{t`Marking the shipment as checked indicates that you have verified that all items included in this shipment are correct`}</Text>
      </Alert>
    ),
    fetchInitialData: false,
    fields: {
      checked_by: {
        hidden: true,
        value: user.getUser()?.pk
      }
    },
    successMessage: t`Shipment marked as checked`,
    onFormSuccess: onSuccess
  });
}

export function useUncheckShipmentForm({
  shipmentId,
  onSuccess
}: {
  shipmentId: number;
  onSuccess: (response: any) => void;
}) {
  return useEditApiFormModal({
    url: ApiEndpoints.sales_order_shipment_list,
    pk: shipmentId,
    title: t`Uncheck Shipment`,
    preFormContent: (
      <Alert color='red' icon={<IconCircleX />} title={t`Uncheck Shipment`}>
        <Text>{t`Marking the shipment as unchecked indicates that the shipment requires further verification`}</Text>
      </Alert>
    ),
    fetchInitialData: false,
    fields: {
      checked_by: {
        hidden: true,
        value: null
      }
    },
    successMessage: t`Shipment marked as unchecked`,
    onFormSuccess: onSuccess
  });
}

export function useCompleteShipmentForm({
  shipment,
  onSuccess
}: {
  shipment: any;
  onSuccess: () => void;
}) {
  const [taskId, setTaskId] = useState<string>('');

  const completeShipmentFields = useSalesOrderShipmentCompleteFields({});

  useBackgroundTask({
    taskId: taskId,
    message: t`Completing shipment`,
    successMessage: t`Shipment completed successfully`,
    onSuccess: onSuccess
  });

  return useCreateApiFormModal({
    url: ApiEndpoints.sales_order_shipment_complete,
    pk: shipment.pk,
    title: t`Complete Shipment`,
    fields: completeShipmentFields,
    focus: 'tracking_number',
    initialData: {
      ...shipment,
      shipment_date: dayjs().format('YYYY-MM-DD')
    },
    successMessage: null,
    onFormSuccess: (response: any) => {
      if (response.task_id) {
        setTaskId(response.task_id);
      } else {
        onSuccess();
      }
    }
  });
}

function SalesOrderAllocateLineRow({
  props,
  record,
  sourceLocation
}: Readonly<{
  props: TableFieldRowProps;
  record: any;
  sourceLocation?: number | null;
}>) {
  // Statically defined field for selecting the stock item
  const stockItemField: ApiFormFieldType = useMemo(() => {
    return {
      field_type: 'related field',
      api_url: apiUrl(ApiEndpoints.stock_item_list),
      model: ModelType.stockitem,
      autoFill: true,
      filters: {
        available: true,
        part_detail: true,
        location_detail: true,
        location: sourceLocation,
        cascade: sourceLocation ? true : undefined,
        part: record.part
      },
      value: props.item.stock_item,
      name: 'stock_item',
      onValueChange: (value: any, instance: any) => {
        props.changeFn(props.rowId, 'stock_item', value);

        // Update the allocated quantity based on the selected stock item
        if (instance) {
          const available = instance.quantity - instance.allocated;
          const required = record.quantity - record.allocated;

          let q = props.item?.quantity ?? 0;

          q = Math.max(q, required);
          q = Math.min(q, available);

          if (q != props.item?.quantity) {
            setQuantity(q);
            props.changeFn(props.rowId, 'quantity', q);
          }
        }
      }
    };
  }, [sourceLocation, record, props]);

  const [quantity, setQuantity] = useState<number | ''>(
    props.item?.quantity ?? ''
  );

  return (
    <Table.Tr key={`table-row-${props.rowId}-${record.pk}`}>
      <Table.Td>
        <RenderPartColumn part={record.part_detail} />
      </Table.Td>
      <Table.Td>
        <ProgressBar
          value={record.allocated}
          maximum={record.quantity}
          progressLabel
        />
      </Table.Td>
      <Table.Td>
        <StandaloneField
          fieldName='stock_item'
          fieldDefinition={stockItemField}
          error={props.rowErrors?.stock_item?.message}
        />
      </Table.Td>
      <Table.Td>
        <TableFieldQuantityInput
          min={0}
          value={quantity}
          onChange={(value) => {
            setQuantity(value);
            props.changeFn(props.rowId, 'quantity', value);
          }}
          error={props.rowErrors?.quantity?.message}
        />
      </Table.Td>
      <Table.Td>
        <RemoveRowButton onClick={() => props.removeFn(props.rowId)} />
      </Table.Td>
    </Table.Tr>
  );
}

export function useAllocateToSalesOrderForm({
  orderId,
  shipmentId,
  lineItems,
  onFormSuccess
}: {
  orderId: number;
  shipmentId?: number;
  lineItems: any[];
  onFormSuccess: (response: any) => void;
}) {
  const [sourceLocation, setSourceLocation] = useState<number | null>(null);

  // Reset source location to known state
  useEffect(() => {
    setSourceLocation(null);
  }, [orderId, shipmentId, lineItems]);

  const fields: ApiFormFieldSet = useMemo(() => {
    return {
      // Non-submitted field to select the source location
      source_location: {
        exclude: true,
        required: false,
        field_type: 'related field',
        api_url: apiUrl(ApiEndpoints.stock_location_list),
        model: ModelType.stocklocation,
        label: t`Source Location`,
        description: t`Select the source location for the stock allocation`,
        onValueChange: (value: any) => {
          setSourceLocation(value);
        }
      },
      items: {
        field_type: 'table',
        value: [],
        headers: [
          { title: t`Part`, style: { minWidth: '200px' } },
          { title: t`Allocated`, style: { minWidth: '200px' } },
          { title: t`Stock Item`, style: { width: '100%' } },
          { title: t`Quantity`, style: { minWidth: '200px' } },
          { title: '', style: { width: '50px' } }
        ],
        modelRenderer: (row: TableFieldRowProps) => {
          const record =
            lineItems.find((item) => item.pk == row.item.line_item) ?? {};

          return (
            <SalesOrderAllocateLineRow
              key={row.rowId}
              props={row}
              record={record}
              sourceLocation={sourceLocation}
            />
          );
        }
      },
      shipment: {
        autoFill: true,
        filters: {
          shipped: false,
          order_detail: true,
          order: orderId
        }
      }
    };
  }, [orderId, shipmentId, lineItems, sourceLocation]);

  return useCreateApiFormModal({
    title: t`Allocate Stock`,
    url: ApiEndpoints.sales_order_allocate,
    pk: orderId,
    fields: fields,
    onFormSuccess: onFormSuccess,
    successMessage: t`Stock items allocated`,
    size: '80%',
    keepOpenOption: true,
    initialData: {
      items: lineItems.map((item) => {
        return {
          id: item.pk,
          line_item: item.pk,
          quantity: 0,
          stock_item: null
        };
      })
    }
  });
}

export function useSalesOrderAllocateSerialsFields({
  itemId,
  orderId
}: {
  itemId: number;
  orderId: number;
}): ApiFormFieldSet {
  return useMemo(() => {
    return {
      line_item: {
        value: itemId,
        hidden: true
      },
      quantity: {},
      serial_numbers: {},
      shipment: {
        filters: {
          order_detail: true,
          order: orderId,
          shipped: false
        }
      }
    };
  }, [itemId, orderId]);
}

export function useSalesOrderShipmentFields({
  customerId,
  pending
}: {
  customerId?: number;
  pending?: boolean;
}): ApiFormFieldSet {
  return useMemo(() => {
    return {
      order: {
        disabled: true
      },
      reference: {},
      shipment_date: {
        hidden: pending ?? true
      },
      delivery_date: {
        hidden: pending ?? true
      },
      shipment_address: {
        placeholder: t`Leave blank to use the order address`,
        filters: {
          company: customerId,
          ordering: '-primary'
        }
      },
      tracking_number: {},
      invoice_number: {},
      tags: TagsField({}),
      link: {}
    };
  }, [customerId, pending]);
}

export function useSalesOrderShipmentCompleteFields({
  shipmentId
}: {
  shipmentId?: number;
}): ApiFormFieldSet {
  return useMemo(() => {
    return {
      shipment_date: {},
      tracking_number: {},
      invoice_number: {},
      link: {}
    };
  }, [shipmentId]);
}

export function useSalesOrderAllocationFields({
  orderId,
  shipment
}: {
  orderId?: number;
  shipment: any;
}): ApiFormFieldSet {
  return useMemo(() => {
    return {
      item: {
        // Cannot change item, but display for reference
        disabled: true
      },
      quantity: {},
      shipment: {
        // Cannot change shipment once it has been shipped
        disabled: !!shipment?.shipment_date,
        // Order ID is required for this field to be accessed
        hidden: !orderId,
        filters: {
          order: orderId,
          shipped: false
        }
      }
    };
  }, [orderId, shipment]);
}

export function useSalesOrderAutoAllocateFields({
  orderId
}: {
  orderId: number;
}): ApiFormFieldSet {
  return useMemo(() => {
    return {
      location: {},
      exclude_location: {},
      interchangeable: {},
      stock_sort_by: {},
      serialized_stock: {},
      shipment: {
        filters: {
          order: orderId,
          shipped: false
        }
      },
      line_items: {
        hidden: true
      }
    };
  }, [orderId]);
}
