import clsx from 'clsx';
import React, { useEffect, useState } from 'react';
import { noop } from '../../../helpers/utils';
import { CommonJsButtonOptions } from '../../Buttons/Button.model';
import {
  ConfirmDialog,
  ConfirmationConfig,
  ConfirmationMode,
} from '../../ConfirmDialog';
import { SvgElement } from '../../VisualElements/SvgElement';
import { BaseFormControl } from '../Form.models';
import { FormElementContainer } from '../FormElementContainer';
import classes from './ToggleButton.scss';

export interface ToggleButtonProps
  extends Omit<CommonJsButtonOptions, 'buttonContext' | 'onButtonClicked'>,
    BaseFormControl {
  /** Current value. Can be used to control state (default: false) */
  value?: boolean;
  /** Whether the 'OFF'/'ON' text is shown (default: true) */
  showONOFFText?: boolean;
  /** Button's height (default: '50px') */
  height?: string | number;
  /** Button's width (default: '100px') */
  width?: string | number;
  /** If set to 'Advanced', action will require confirmation via a confirmation pop up. (default: 'None') */
  confirmationMode?: Extract<ConfirmationMode, 'None' | 'Advanced'>;
  /** Optional text overrides for the confirmation pop up. */
  confirmationConfig?: ConfirmationConfig;
  /** Event to raise when the button is clicked. Selected state is return as a second argument */
  onButtonClicked?: (
    event: React.MouseEvent<HTMLButtonElement, MouseEvent>,
    value: boolean,
  ) => void;
}

/**
 * A toggle that switches between true and false
 * @example
 * <ToggleButton type="button" onButtonClicked={(e, v) => console.log(e, v)}/>
 */
export const ToggleButton: React.FC<ToggleButtonProps> = ({
  value = false,
  showONOFFText = true,
  type = 'button',
  height,
  width,
  disabled = false,
  className,
  confirmationMode = 'None',
  confirmationConfig = {},
  onButtonClicked = noop,
  ...rest
}: ToggleButtonProps) => {
  const [selected, setSelected] = useState<boolean>(value);

  const [confirmation, setConfirmation] = useState<boolean>(false);
  const [referenceElement, setReferenceElement] = useState<HTMLElement>();

  useEffect(() => {
    setSelected(value);
  }, [value]);

  const customStyles = {
    height,
    width,
    gridTemplateRows: height,
  } as React.CSSProperties;

  const { title, body, cancelButtonText, confirmButtonText, onConfirmOpen } =
    confirmationConfig;

  const onClickHandler = (
    event: React.MouseEvent<HTMLButtonElement, MouseEvent>,
  ): void => {
    if (confirmationMode === 'None') {
      event.persist();
      setSelected((prevState) => {
        onButtonClicked(event, !prevState);
        return !prevState;
      });
    } else {
      setConfirmation(true);
    }
  };

  const onConfirmHandler = (
    event: React.MouseEvent<HTMLButtonElement, MouseEvent>,
  ): void => {
    setConfirmation(false);
    event.persist();
    setSelected((prevState) => {
      onButtonClicked(event, !prevState);
      return !prevState;
    });
  };

  return (
    <>
      <FormElementContainer
        {...rest}
        className={clsx(
          classes.container,
          'toggle-button-container',
          className,
        )}
        dataTestFieldType="ToggleButton"
        htmlFor={rest.id ?? rest.name}
      >
        <button
          id={rest.id ?? rest.name}
          className={clsx(classes.toggle, {
            [classes.hasConfirm]: confirmation,
          })}
          type={type}
          style={customStyles}
          disabled={disabled}
          ref={setReferenceElement as React.LegacyRef<HTMLButtonElement>}
          onClick={onClickHandler}
          data-test-checked={selected}
        >
          <div className={clsx(classes.off, { [classes.active]: !selected })}>
            <SvgElement viewBox="0 0 40 40">
              {showONOFFText && !selected && (
                <g className={classes.svgText}>
                  <OffIcon />
                </g>
              )}
            </SvgElement>
          </div>
          <div className={clsx(classes.on, { [classes.active]: selected })}>
            <SvgElement viewBox="0 0 40 40">
              {showONOFFText && selected && (
                <g className={classes.svgText}>
                  <OnIcon />
                </g>
              )}
            </SvgElement>
          </div>
        </button>
        {confirmation && (
          <ConfirmDialog
            className={classes.confirmDialog}
            referenceElement={referenceElement}
            title={title}
            cancelButtonText={cancelButtonText}
            confirmButtonText={confirmButtonText}
            onCancel={() => setConfirmation(false)}
            onConfirm={onConfirmHandler}
            onConfirmOpen={onConfirmOpen}
          >
            {body}
          </ConfirmDialog>
        )}
      </FormElementContainer>
    </>
  );
};

const OffIcon: React.FC = () => (
  <>
    <path
      d="M6.5,20.1c0-1,0.2-1.9,0.5-2.6c0.2-0.5,0.5-1,0.9-1.4c0.4-0.4,0.8-0.7,1.3-0.9c0.6-0.3,1.4-0.4,2.2-0.4
c1.5,0,2.7,0.5,3.6,1.4c0.9,0.9,1.3,2.2,1.3,3.8c0,1.6-0.4,2.9-1.3,3.8c-0.9,0.9-2.1,1.4-3.6,1.4c-1.5,0-2.7-0.5-3.6-1.4
S6.5,21.7,6.5,20.1z M8.6,20c0,1.1,0.3,2,0.8,2.6c0.5,0.6,1.2,0.9,2,0.9c0.8,0,1.5-0.3,2-0.9c0.5-0.6,0.8-1.5,0.8-2.6
c0-1.1-0.3-2-0.8-2.6s-1.2-0.8-2-0.8c-0.8,0-1.5,0.3-2,0.9C8.8,18,8.6,18.8,8.6,20z"
    />
    <path d="M17.9,25V15h6.9v1.7H20v2.4h4.2v1.7H20V25H17.9z" />
    <path d="M26.6,25V15h6.9v1.7h-4.9v2.4h4.2v1.7h-4.2V25H26.6z" />
  </>
);

const OnIcon: React.FC = () => (
  <>
    <path
      d="M10.4,20.1c0-1,0.2-1.9,0.5-2.6c0.2-0.5,0.5-1,0.9-1.4s0.8-0.7,1.3-0.9c0.6-0.3,1.3-0.4,2.2-0.4
c1.5,0,2.7,0.5,3.5,1.4s1.3,2.2,1.3,3.8c0,1.6-0.4,2.9-1.3,3.8c-0.9,0.9-2.1,1.4-3.5,1.4c-1.5,0-2.7-0.5-3.6-1.4
C10.8,22.9,10.4,21.7,10.4,20.1z M12.4,20c0,1.1,0.3,2,0.8,2.6c0.5,0.6,1.2,0.9,2,0.9s1.5-0.3,2-0.9C17.7,22,18,21.1,18,20
c0-1.1-0.3-2-0.8-2.6s-1.2-0.8-2-0.8s-1.5,0.3-2,0.9C12.7,18,12.4,18.8,12.4,20z"
    />
    <path d="M21.7,25V15h2l4.1,6.7V15h1.9v10h-2l-4-6.5V25H21.7z" />
  </>
);
