import {Component} from 'react';

import TextField from 'sentry/components/forms/fields/textField';
import {DataCategory} from 'sentry/types/core';

import type {
  AdminConfirmParams,
  AdminConfirmRenderProps,
} from 'admin/components/adminConfirmationModal';
import {MAX_ADMIN_CATEGORY_GIFTS} from 'getsentry/constants';
import type {Subscription} from 'getsentry/types';
import {getPlanCategoryName} from 'getsentry/utils/dataCategory';

/** @internal exported for tests only */
export const FREE_EVENTS_KEYS = {
  [DataCategory.ERRORS]: 'addFreeErrors',
  [DataCategory.TRANSACTIONS]: 'addFreeTransactions',
  [DataCategory.REPLAYS]: 'addFreeReplays',
  [DataCategory.ATTACHMENTS]: 'addFreeAttachments',
  [DataCategory.MONITOR_SEATS]: 'addFreeMonitorSeats',
  [DataCategory.UPTIME]: 'addFreeUptime',
  [DataCategory.SPANS]: 'addFreeSpans',
  [DataCategory.SPANS_INDEXED]: 'addFreeSpansIndexed',
  [DataCategory.PROFILE_DURATION]: 'addFreeProfileDuration',
};

/**
 * Used so form can show "How many errors in multiples of 1,000s? (50 is 50,000 errors)"
 * and calculate total based on the multiplier
 */
const DISPLAY_FREE_EVENTS_MULTIPLE = {
  [DataCategory.ERRORS]: 1_000,
  [DataCategory.TRANSACTIONS]: 1_000,
  [DataCategory.REPLAYS]: 1,
  [DataCategory.ATTACHMENTS]: 1, // GB
  [DataCategory.MONITOR_SEATS]: 1,
  [DataCategory.UPTIME]: 1,
  [DataCategory.SPANS]: 100_000,
  [DataCategory.SPANS_INDEXED]: 100_000,
  [DataCategory.PROFILE_DURATION]: 1, // hours
};

type Props = AdminConfirmRenderProps & {
  dataCategory: DataCategory;
  subscription: Subscription;
};

type State = {
  freeEvents?: number;
};

/**
 * Rendered as part of a openAdminConfirmModal call
 */
class AddGiftEventsAction extends Component<Props, State> {
  state: State = {
    freeEvents: undefined,
  };

  componentDidMount() {
    this.props.setConfirmCallback(this.handleConfirm);
    this.props.disableConfirmButton(true);
  }

  handleChange = (value: string) => {
    const freeEvents = this.coerceValue(value);
    this.props.disableConfirmButton(freeEvents === 0);
    this.setState({freeEvents});
  };

  coerceValue(value: string) {
    const {dataCategory} = this.props;

    const intValue = parseInt(value, 10);
    const maxValue =
      // @ts-expect-error TS(7053): Element implicitly has an 'any' type because expre... Remove this comment to see the full error message
      MAX_ADMIN_CATEGORY_GIFTS[dataCategory] / DISPLAY_FREE_EVENTS_MULTIPLE[dataCategory];

    if (isNaN(intValue) || intValue < 0) {
      return undefined;
    }

    return intValue > maxValue ? maxValue : intValue;
  }

  handleConfirm = (params: AdminConfirmParams) => {
    const {onConfirm, dataCategory} = this.props;

    const freeEvents = this.calculatedTotal;
    // @ts-expect-error TS(7053): Element implicitly has an 'any' type because expre... Remove this comment to see the full error message
    const freeEventsKey = FREE_EVENTS_KEYS[dataCategory];

    onConfirm?.({[freeEventsKey]: freeEvents, ...params});

    this.resetValue();
  };

  resetValue = () => {
    this.setState({freeEvents: 0});
  };

  get calculatedTotal() {
    const {dataCategory} = this.props;
    const {freeEvents} = this.state;

    if (!freeEvents) {
      return 0;
    }
    // @ts-expect-error TS(7053): Element implicitly has an 'any' type because expre... Remove this comment to see the full error message
    return freeEvents * DISPLAY_FREE_EVENTS_MULTIPLE[dataCategory];
  }

  render() {
    const {dataCategory, subscription} = this.props;
    const {freeEvents} = this.state;

    function getlabel() {
      if (dataCategory === DataCategory.ATTACHMENTS) {
        return 'How many attachments in GB?';
      }
      if (dataCategory === DataCategory.PROFILE_DURATION) {
        return 'How many profile hours?';
      }
      const categoryName = getPlanCategoryName({
        plan: subscription.planDetails,
        category: dataCategory,
        capitalize: false,
      });
      // @ts-expect-error TS(7053): Element implicitly has an 'any' type because expre... Remove this comment to see the full error message
      const multiplier = DISPLAY_FREE_EVENTS_MULTIPLE[dataCategory];
      const addToMessage =
        multiplier > 1
          ? ` in multiples of ${multiplier.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',')}s?`
          : '?';
      return `How many ${categoryName}${addToMessage} (50 is ${(50 * multiplier).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',')} ${categoryName})`;
    }

    const total = this.calculatedTotal.toLocaleString();
    function getHelp() {
      let postFix = '';
      if (dataCategory === DataCategory.PROFILE_DURATION) {
        if (total === '1') {
          postFix = ' hour';
        } else {
          postFix = ' hours';
        }
      }
      if (dataCategory === DataCategory.ATTACHMENTS) {
        postFix = ' GB';
      }
      return `Total: ${total}${postFix}`;
    }

    return (
      <TextField
        autoFocus
        inline={false}
        stacked
        flexibleControlStateSize
        data-test-id={`num-free-${dataCategory}`}
        label={getlabel()}
        help={getHelp()}
        name={dataCategory}
        inputMode="numeric"
        pattern="[0-9]*"
        maxLength={dataCategory === DataCategory.REPLAYS ? 7 : 5}
        value={freeEvents && !isNaN(freeEvents) ? freeEvents.toString() : ''}
        onChange={this.handleChange}
      />
    );
  }
}

export default AddGiftEventsAction;