import React, { useEffect, useState } from 'react';
import PropTypes from 'prop-types';
import { useDispatch, useSelector } from 'react-redux';
import dayjs from 'dayjs';
import { Add } from '@mui/icons-material';

import {
  DEMAND_TAG_FORMAT,
  DEMAND_TAG_HB_GAM_PLATFORMS,
  DEMAND_TAG_PAGE_AD_SERVING_BUSINESS_MODEL_LIST,
  DEMAND_TAG_PAGE_AD_SERVING_BUSINESS_MODEL_REV_SHARE,
  DEMAND_TAG_PAGE_BUSINESS_MODEL_HB_NOT_GAM,
  DEMAND_TAG_PAGE_TYPE_VALUES,
  DEMAND_TAG_PRICING_TYPE,
} from '@/modules/marketplace/account/constants';

import * as selectors from '../../../../redux/selectors';
import * as actions from '../../../../redux/slices';
import { definePricingTableKey } from '@/modules/marketplace/account/helpers/createDemandTagPriceRequestBody';
import { parseNumberWithRound } from '@/modules/marketplace/common/helpers';

import { Form, FormContent, FormGroupTitle, FormRow, FormSection } from '@/modules/@common/Form';
import BusinessModel from './components/BusinessModel/index';
import FormLineItem from './components/FormLineItem/index';
import LineItem from './components/LineItem';
import { Button, Divider, Stack, TablePagination } from '@/mui/components';

function PricingTab(props) {
  const dispatch = useDispatch();

  const settings = useSelector(selectors.settingsSelector);
  const { format, platform, type: tagType } = settings;

  const pricing = useSelector(selectors.pricingSelector);

  const {
    model,
    type,
    fixedRpmRateTable,
    adServingFeesTable,
    additionalFeesTable,
    adRequestFeesTable,
    publisherDemand,
  } = pricing;

  const pageConfig = useSelector(selectors.pageConfigSelector);
  const demandAccountInfo = useSelector(selectors.demandAccountInfoSelector);

  const { isCreatingNew, isDuplicate } = pageConfig ?? {};
  const [showNewRPMForm, toggleNewRPMForm] = useState(false);
  const [showNewAdServingForm, toggleNewAdServingForm] = useState(false);
  const [showNewAdditionalForm, toggleNewAdditionalForm] = useState(false);
  const [showNewAdRequestForm, toggleNewAdRequestForm] = useState(false);

  const defaultRate =
    format === DEMAND_TAG_FORMAT.video
      ? demandAccountInfo?.defaultValues?.videoAdServingFee
      : demandAccountInfo?.defaultValues?.displayAdServingFee;

  const getStateMetadataByType = (typeParam) => ({
    tableKey: definePricingTableKey(typeParam),
    tableState: pricing[definePricingTableKey(typeParam)],
  });

  const onChangePage = (typeParam, page) => {
    const { tableKey, tableState } = getStateMetadataByType(typeParam);

    dispatch(
      actions.setPricingTabAction({
        [tableKey]: {
          ...tableState,
          page: page - 1,
        },
      }),
    );

    dispatch(actions.getDemandTagPricingAction(typeParam));
  };

  const onChangeRowsPerPage = (typeParam, rows) => {
    const { tableKey, tableState } = getStateMetadataByType(typeParam);

    dispatch(
      actions.setPricingTabAction({
        [tableKey]: {
          ...tableState,
          rowsPerPage: rows,
          page: 0,
        },
      }),
    );

    dispatch(actions.getDemandTagPricingAction(typeParam));
  };

  const onAddNewPrice = (typeParam, data, removePrevItems = false) => {
    const { tableKey, tableState } = getStateMetadataByType(typeParam);
    const prepareData = {
      id: tableState.rows.length,
      ...data,
      value: parseFloat(data.rate),
    };

    if (isCreatingNew || isDuplicate) {
      dispatch(
        actions.setPricingTabAction({
          [tableKey]: {
            ...tableState,
            rows: [prepareData, ...(removePrevItems ? [] : tableState.rows)],
          },
        }),
      );
    } else {
      // update with server
      dispatch(
        actions.updateDemandTagAction({
          type: typeParam,
          data: prepareData,
        }),
      );
    }
  };

  const onEditPrice = (typeParam, data) => {
    const { tableKey, tableState } = getStateMetadataByType(typeParam);

    dispatch(
      actions.setPricingTabAction({
        [tableKey]: {
          ...tableState,
          rows: tableState.rows.map((i) => (i.id === data.id ? { ...data, value: parseFloat(data.rate) } : i)),
        },
      }),
    );
  };

  const onRemovePrice = (typeParam, id) => {
    const { tableKey, tableState } = getStateMetadataByType(typeParam);

    dispatch(
      actions.setPricingTabAction({
        [tableKey]: {
          ...tableState,
          rows: tableState.rows.filter((i) => i.id !== id),
        },
      }),
    );
  };

  useEffect(() => {
    dispatch(actions.getDemandAccountByIdAction());
  }, []);

  useEffect(() => {
    if (!props.isAdminMP && (isCreatingNew || isDuplicate)) {
      const modelAdServing =
        demandAccountInfo?.defaultValues?.adServingModel || DEMAND_TAG_PAGE_AD_SERVING_BUSINESS_MODEL_LIST[0].value;

      onAddNewPrice(
        DEMAND_TAG_PRICING_TYPE.adServing,
        {
          model: modelAdServing,
          rate: defaultRate,
          startDate: new Date().getTime(),
          endDate: null,
          status: 'active',
        },
        true,
      );
    }
  }, [defaultRate]);

  return (
    <Form>
      <FormContent>
        <FormSection>
          <FormGroupTitle>Business Model</FormGroupTitle>
          <BusinessModel
            model={model}
            type={type}
            disabled={
              tagType === DEMAND_TAG_PAGE_TYPE_VALUES.hb &&
              !DEMAND_TAG_HB_GAM_PLATFORMS.includes(platform?.code) &&
              !(isCreatingNew || isDuplicate)
            }
          />

          {model !== DEMAND_TAG_PAGE_BUSINESS_MODEL_HB_NOT_GAM[0].value && (
            <>
              <Divider flexItem />
              <FormRow label="RPM Rate" justifyContent="flex-end" fullWidth>
                {!!fixedRpmRateTable.rows.length && !isDuplicate && (
                  <Button
                    size="small"
                    onClick={() => {
                      if (!isCreatingNew) {
                        onChangePage(DEMAND_TAG_PRICING_TYPE.price, 1);
                      }
                      toggleNewRPMForm(true);
                    }}
                    startIcon={<Add />}
                    disabled={showNewRPMForm || (isCreatingNew && fixedRpmRateTable.rows.length === 1)}
                  >
                    New
                  </Button>
                )}
                {!fixedRpmRateTable.rows.length && !showNewRPMForm && (
                  <Button
                    size="small"
                    onClick={() => {
                      if (!isCreatingNew) {
                        onChangePage(DEMAND_TAG_PRICING_TYPE.price, 1);
                      }
                      toggleNewRPMForm(true);
                    }}
                    data-id="add-new-line-item"
                    startIcon={<Add />}
                  >
                    Add Fixed RPM Rate
                  </Button>
                )}
              </FormRow>
            </>
          )}

          {model !== DEMAND_TAG_PAGE_BUSINESS_MODEL_HB_NOT_GAM[0].value && (
            <FormRow fullWidth>
              <Stack fullWidth>
                <LineItem
                  id="title"
                  rate="Rate"
                  startDate="Start Date"
                  endDate="End Date"
                  updatedBy="Updated By"
                  itemType={DEMAND_TAG_PRICING_TYPE.price}
                  isLabelRow
                />
                {showNewRPMForm && (
                  <FormLineItem
                    isCreatingNew={isCreatingNew}
                    itemType={DEMAND_TAG_PRICING_TYPE.price}
                    prevStartDate={fixedRpmRateTable.rows[0] ? fixedRpmRateTable.rows[0].startDate : 0}
                    onSubmit={(data) => {
                      toggleNewRPMForm(false);
                      onAddNewPrice(DEMAND_TAG_PRICING_TYPE.price, data);
                    }}
                    onCancel={() => {
                      toggleNewRPMForm(false);
                    }}
                  />
                )}
                {fixedRpmRateTable.rows.map((item) => (
                  <LineItem
                    key={item.startDate}
                    id={item.id}
                    rate={Math.round(item.value * 100) / 100}
                    startDate={item.startDate}
                    endDate={item.endDate}
                    updatedBy={item.updatedBy}
                    status={item.status}
                    rateMask="$[NUMBER]"
                    isCreatingNew={isCreatingNew}
                    itemType={DEMAND_TAG_PRICING_TYPE.price}
                    isDuplicating={isDuplicate}
                    onSubmit={(data) => {
                      onEditPrice(DEMAND_TAG_PRICING_TYPE.price, data);
                    }}
                    onDelete={(id) => {
                      onRemovePrice(DEMAND_TAG_PRICING_TYPE.price, id);
                    }}
                  />
                ))}

                {!isCreatingNew && !isDuplicate && !!fixedRpmRateTable.rows.length && (
                  <TablePagination
                    component="div"
                    rowsPerPageOptions={[5, 10, 25]}
                    count={fixedRpmRateTable.totalCount}
                    rowsPerPage={fixedRpmRateTable.rowsPerPage}
                    page={fixedRpmRateTable.page + 1}
                    onPageChange={(event, page) => {
                      onChangePage(DEMAND_TAG_PRICING_TYPE.price, page);
                    }}
                    onRowsPerPageChange={(event) => {
                      onChangeRowsPerPage(DEMAND_TAG_PRICING_TYPE.price, +event.target.value);
                    }}
                  />
                )}
              </Stack>
            </FormRow>
          )}

          {publisherDemand !== false && props.isAdminMP && (
            <>
              <Divider flexItem />
              <FormRow label="Ad Serving Fees" fullWidth justifyContent="flex-end">
                {!!adServingFeesTable.rows.length && !isDuplicate && (
                  <Button
                    size="small"
                    onClick={() => {
                      if (!isCreatingNew) {
                        onChangePage(DEMAND_TAG_PRICING_TYPE.adServing, 1);
                      }
                      toggleNewAdServingForm(true);
                    }}
                    data-id="add-new-line-item"
                    startIcon={<Add />}
                    disabled={showNewAdServingForm || (isCreatingNew && adServingFeesTable.rows.length === 1)}
                  >
                    New
                  </Button>
                )}
                {!adServingFeesTable.rows.length && !showNewAdServingForm && (
                  <Button
                    size="small"
                    onClick={() => {
                      if (!isCreatingNew) {
                        onChangePage(DEMAND_TAG_PRICING_TYPE.adServing, 1);
                      }
                      toggleNewAdServingForm(true);
                    }}
                    data-id="add-new-line-item"
                    startIcon={<Add />}
                  >
                    Add Serving Fees
                  </Button>
                )}
              </FormRow>
              <FormRow fullWidth>
                <Stack fullWidth>
                  <LineItem
                    id="title"
                    model="Business Model"
                    rate="Ad Serving Rate"
                    startDate="Start Date"
                    endDate="End Date"
                    updatedBy="Updated By"
                    itemType={DEMAND_TAG_PRICING_TYPE.adServing}
                    isLabelRow
                  />
                  {showNewAdServingForm && (
                    <FormLineItem
                      isCreatingNew={isCreatingNew}
                      itemType={DEMAND_TAG_PRICING_TYPE.adServing}
                      prevStartDate={adServingFeesTable.rows[0] ? adServingFeesTable.rows[0].startDate : 0}
                      onSubmit={(data) => {
                        const price = {
                          ...data,
                          rate:
                            data.model === DEMAND_TAG_PAGE_AD_SERVING_BUSINESS_MODEL_REV_SHARE
                              ? parseNumberWithRound(data.rate / 100)
                              : data.rate,
                        };
                        toggleNewAdServingForm(false);
                        onAddNewPrice(DEMAND_TAG_PRICING_TYPE.adServing, price);
                      }}
                      onCancel={() => {
                        toggleNewAdServingForm(false);
                      }}
                      isZeroAllowed
                      defaultRate={
                        demandAccountInfo?.defaultValues?.adServingModel ===
                        DEMAND_TAG_PAGE_AD_SERVING_BUSINESS_MODEL_REV_SHARE
                          ? parseNumberWithRound(defaultRate * 100)
                          : defaultRate
                      }
                      defaultModel={demandAccountInfo?.defaultValues?.adServingModel}
                    />
                  )}
                  {adServingFeesTable.rows.map((item) => (
                    <LineItem
                      key={item.startDate}
                      id={item.id}
                      model={item.model}
                      rate={
                        item.model === DEMAND_TAG_PAGE_AD_SERVING_BUSINESS_MODEL_REV_SHARE
                          ? parseNumberWithRound(item.value * 100)
                          : item.value
                      }
                      startDate={item.startDate}
                      endDate={item.endDate}
                      status={item.status}
                      updatedBy={item.updatedBy}
                      rateMask={
                        item.model === DEMAND_TAG_PAGE_AD_SERVING_BUSINESS_MODEL_REV_SHARE ? '[NUMBER]%' : '$[NUMBER]'
                      }
                      isCreatingNew={isCreatingNew}
                      itemType={DEMAND_TAG_PRICING_TYPE.adServing}
                      isDuplicating={isDuplicate}
                      onSubmit={(data) => {
                        const price = {
                          ...data,
                          rate:
                            data.model === DEMAND_TAG_PAGE_AD_SERVING_BUSINESS_MODEL_REV_SHARE
                              ? parseNumberWithRound(data.rate / 100)
                              : data.rate,
                        };
                        onEditPrice(DEMAND_TAG_PRICING_TYPE.adServing, price);
                      }}
                      onDelete={(id) => {
                        onRemovePrice(DEMAND_TAG_PRICING_TYPE.adServing, id);
                      }}
                    />
                  ))}

                  {!isCreatingNew && !isDuplicate && !!adServingFeesTable.rows.length && (
                    <TablePagination
                      component="div"
                      rowsPerPageOptions={[5, 10, 25]}
                      count={adServingFeesTable.totalCount}
                      rowsPerPage={adServingFeesTable.rowsPerPage}
                      page={adServingFeesTable.page + 1}
                      onPageChange={(event, page) => {
                        onChangePage(DEMAND_TAG_PRICING_TYPE.adServing, page);
                      }}
                      onRowsPerPageChange={(event) => {
                        onChangeRowsPerPage(DEMAND_TAG_PRICING_TYPE.adServing, +event.target.value);
                      }}
                    />
                  )}
                </Stack>
              </FormRow>
            </>
          )}

          {publisherDemand !== true &&
            format === DEMAND_TAG_FORMAT.display &&
            DEMAND_TAG_HB_GAM_PLATFORMS.includes(platform.code) && (
              <>
                <Divider flexItem />
                <FormRow label="Google Unfilled Ad Requests Fee" fullWidth justifyContent="flex-end">
                  {!adRequestFeesTable.rows.length && !showNewAdRequestForm && (
                    <Button
                      size="small"
                      onClick={() => {
                        if (!isCreatingNew) {
                          onChangePage(DEMAND_TAG_PRICING_TYPE.adRequest, 1);
                        }
                        toggleNewAdRequestForm(true);
                      }}
                      data-id="add-new-line-item"
                      startIcon={<Add />}
                      disabled={!isCreatingNew}
                    >
                      Add Google Unfilled Fee
                    </Button>
                  )}
                </FormRow>
                <FormRow fullWidth>
                  <Stack fullWidth>
                    <LineItem
                      id="title"
                      rate="Unfilled Rate"
                      startDate="Start Date"
                      endDate=""
                      updatedBy="Updated By"
                      itemType={DEMAND_TAG_PRICING_TYPE.adRequest}
                      isLabelRow
                    />
                    {showNewAdRequestForm && (
                      <FormLineItem
                        isCreatingNew={isCreatingNew}
                        itemType={DEMAND_TAG_PRICING_TYPE.adRequest}
                        prevStartDate={adRequestFeesTable.rows[0] ? adRequestFeesTable.rows[0].startDate : 0}
                        onSubmit={(data) => {
                          toggleNewAdRequestForm(false);
                          onAddNewPrice(DEMAND_TAG_PRICING_TYPE.adRequest, data);
                        }}
                        onCancel={() => {
                          toggleNewAdRequestForm(false);
                        }}
                      />
                    )}
                    {adRequestFeesTable.rows.map((item) => (
                      <LineItem
                        key={item.startDate}
                        id={item.id}
                        rate={item.value}
                        startDate={item.startDate}
                        endDate={item.endDate}
                        status={item.status}
                        updatedBy={item.updatedBy}
                        rateMask="$[NUMBER]"
                        isCreatingNew={isCreatingNew}
                        itemType={DEMAND_TAG_PRICING_TYPE.adRequest}
                        isDuplicating={isDuplicate}
                        onSubmit={(data) => {
                          onEditPrice(DEMAND_TAG_PRICING_TYPE.adRequest, data);
                        }}
                        onDelete={(id) => {
                          onRemovePrice(DEMAND_TAG_PRICING_TYPE.adRequest, id);
                        }}
                      />
                    ))}

                    {!isCreatingNew && !isDuplicate && !!adRequestFeesTable.rows.length && (
                      <TablePagination
                        component="div"
                        rowsPerPageOptions={[5, 10, 25]}
                        count={adRequestFeesTable.totalCount}
                        rowsPerPage={adRequestFeesTable.rowsPerPage}
                        page={adRequestFeesTable.page + 1}
                        onPageChange={(event, page) => {
                          onChangePage(DEMAND_TAG_PRICING_TYPE.adRequest, page);
                        }}
                        onRowsPerPageChange={(event) => {
                          onChangeRowsPerPage(DEMAND_TAG_PRICING_TYPE.adRequest, +event.target.value);
                        }}
                      />
                    )}
                  </Stack>
                </FormRow>
              </>
            )}

          {props.isAdminMP && (
            <>
              <Divider flexItem />
              <FormRow label="Additional Fees" fullWidth justifyContent="flex-end">
                {!!additionalFeesTable.rows.length && !isDuplicate && (
                  <Button
                    size="small"
                    onClick={() => {
                      if (!isCreatingNew) {
                        onChangePage(DEMAND_TAG_PRICING_TYPE.fee, 1);
                      }
                      toggleNewAdditionalForm(true);
                    }}
                    data-id="add-new-line-item"
                    startIcon={<Add />}
                    disabled={showNewAdditionalForm || (isCreatingNew && additionalFeesTable.rows.length === 1)}
                  >
                    New
                  </Button>
                )}
                {!additionalFeesTable.rows.length && !showNewAdditionalForm && (
                  <Button
                    size="small"
                    onClick={() => {
                      if (!isCreatingNew) {
                        onChangePage(DEMAND_TAG_PRICING_TYPE.fee, 1);
                      }
                      toggleNewAdditionalForm(true);
                    }}
                    data-id="add-new-line-item"
                    startIcon={<Add />}
                  >
                    Add Additional Fees
                  </Button>
                )}
              </FormRow>
              <FormRow fullWidth>
                <Stack fullWidth>
                  <LineItem
                    id="title"
                    rate="Additional Fees %"
                    startDate="Start Date"
                    endDate="End Date"
                    updatedBy="Updated By"
                    itemType={DEMAND_TAG_PRICING_TYPE.fee}
                    isLabelRow
                  />
                  {showNewAdditionalForm && (
                    <FormLineItem
                      isCreatingNew={isCreatingNew}
                      isEditableEndDate
                      itemType={DEMAND_TAG_PRICING_TYPE.fee}
                      prevStartDate={additionalFeesTable.rows[0] ? additionalFeesTable.rows[0].startDate : 0}
                      onSubmit={(data) => {
                        toggleNewAdditionalForm(false);
                        onAddNewPrice(DEMAND_TAG_PRICING_TYPE.fee, {
                          ...data,
                          rate: parseNumberWithRound(data.rate / 100),
                        });
                      }}
                      onCancel={() => {
                        toggleNewAdditionalForm(false);
                      }}
                    />
                  )}
                  {additionalFeesTable.rows.map((item, index) => {
                    const canUpdateEndDate =
                      additionalFeesTable.page === 0 &&
                      index === 0 &&
                      ((item.endDate && dayjs(item.endDate).isAfter(new Date().getTime())) || !item.endDate);
                    // only the last one can be edited and fee end date > current time
                    // cannot be edited if fee is already closed
                    return (
                      <LineItem
                        key={item.startDate}
                        id={item.id}
                        rate={parseNumberWithRound(item.value * 100)}
                        startDate={item.startDate}
                        endDate={item.endDate}
                        status={item.status}
                        updatedBy={item.updatedBy}
                        rateMask="[NUMBER]%"
                        isCreatingNew={isCreatingNew}
                        itemType={DEMAND_TAG_PRICING_TYPE.fee}
                        isDuplicating={isDuplicate}
                        canUpdateEndDate={canUpdateEndDate}
                        onSubmit={(data) => {
                          onEditPrice(DEMAND_TAG_PRICING_TYPE.fee, {
                            ...data,
                            rate: parseNumberWithRound(data.rate / 100),
                          });
                          // updating end date for last fee
                          if (canUpdateEndDate && !isCreatingNew && !isDuplicate) {
                            onAddNewPrice(DEMAND_TAG_PRICING_TYPE.fee, {
                              ...data,
                              startDate: null, // server update fee only without startDate
                              rate: null, // server update fee only without value
                            });
                          }
                        }}
                        onDelete={(id) => {
                          onRemovePrice(DEMAND_TAG_PRICING_TYPE.fee, id);
                        }}
                      />
                    );
                  })}
                  {!isCreatingNew && !isDuplicate && !!additionalFeesTable.rows.length && (
                    <TablePagination
                      component="div"
                      rowsPerPageOptions={[5, 10, 25]}
                      count={additionalFeesTable.totalCount}
                      rowsPerPage={additionalFeesTable.rowsPerPage}
                      page={additionalFeesTable.page + 1}
                      onPageChange={(event, page) => {
                        onChangePage(DEMAND_TAG_PRICING_TYPE.fee, page);
                      }}
                      onRowsPerPageChange={(event) => {
                        onChangeRowsPerPage(DEMAND_TAG_PRICING_TYPE.fee, +event.target.value);
                      }}
                    />
                  )}
                </Stack>
              </FormRow>
            </>
          )}
        </FormSection>
      </FormContent>
    </Form>
  );
}

PricingTab.propTypes = {
  isAdminMP: PropTypes.bool.isRequired,
};

export default PricingTab;
