// deps-lint-skip-all
import { CSSInterpolation, Keyframes } from '@ant-design/cssinjs';
import { TinyColor } from '@ctrl/tinycolor';
import {
  DerivativeToken,
  useStyleRegister,
  useToken,
  resetComponent,
  UseComponentStyleResult,
} from '../../_util/theme';
import { GlobalToken } from '../../_util/theme/interface';

// ============================== Tokens ==============================
interface RadioToken extends DerivativeToken {
  radioFocusShadow: string;
  radioButtonFocusShadow: string;

  radioSize: number;
  radioTop: string;
  radioDotSize: number;
  radioDotColor: string;
  radioDotDisabledColor: string;
  radioSolidCheckedColor: string;

  radioButtonBg: string;
  radioButtonCheckedBg: string;
  radioButtonColor: string;
  radioButtonHoverColor: string;
  radioButtonActiveColor: string;
  radioButtonPaddingHorizontal: number;
  radioDisabledButtonCheckedBg: string;
  radioDisabledButtonCheckedColor: string;
  radioWrapperMarginRight: number;
}

function getRadioToken(token: GlobalToken) {
  // Radio
  const radioFocusShadow = `0 0 0 3px ${token.colorPrimaryOutline}`;
  const radioButtonFocusShadow = radioFocusShadow;

  const radioSize = token.fontSizeLG;
  // FIXME: hard code
  const radioTop = '0.2em';
  // FIXME: hard code
  const radioDotSize = radioSize - 8;
  const radioDotColor = token.colorPrimary;
  // FIXME: hard code
  const radioDotDisabledColor = new TinyColor('#000').setAlpha(0.2).toRgbString();
  const radioSolidCheckedColor = token.colorBgComponent;

  // Radio buttons
  const radioButtonBg = token.colorBgComponent;
  const radioButtonCheckedBg = token.colorBgComponent;
  const radioButtonColor = token.colorText;
  const radioButtonHoverColor = token.colorPrimaryHover;
  const radioButtonActiveColor = token.colorPrimaryActive;
  // FIXME: hard code
  const radioButtonPaddingHorizontal = token.padding - 1;
  // FIXME: hard code
  const radioDisabledButtonCheckedBg = new TinyColor('#000').tint(90).toRgbString();
  const radioDisabledButtonCheckedColor = token.colorTextDisabled;
  const radioWrapperMarginRight = token.marginXS;

  return {
    ...token,

    radioFocusShadow,
    radioButtonFocusShadow,
    radioSize,
    radioTop,
    radioDotSize,
    radioDotColor,
    radioDotDisabledColor,
    radioSolidCheckedColor,
    radioButtonBg,
    radioButtonCheckedBg,
    radioButtonColor,
    radioButtonHoverColor,
    radioButtonActiveColor,
    radioButtonPaddingHorizontal,
    radioDisabledButtonCheckedBg,
    radioDisabledButtonCheckedColor,
    radioWrapperMarginRight,
  };
}

// ============================== Styles ==============================
const antRadioEffect = new Keyframes('antRadioEffect', {
  '0%': { transform: 'scale(1)', opacity: 0.5 },
  '100%': { transform: 'scale(1.6)', opacity: 0 },
});

// styles from RadioGroup only
function getGroupRadioStyle(
  prefixCls: string,
  antPrefix: string,
  token: DerivativeToken,
): CSSInterpolation {
  const groupPrefixCls = `${prefixCls}-group`;

  return {
    [`.${groupPrefixCls}`]: {
      ...resetComponent(token),
      display: 'inline-block',
      fontSize: 0,

      // RTL
      '&&-rtl': {
        direction: 'rtl',
      },

      [`.${antPrefix}-badge .${antPrefix}-badge-count`]: {
        zIndex: 1,
      },

      [`> .${antPrefix}-badge:not(:first-child) > .${prefixCls}-button-wrapper`]: {
        borderInlineStart: 'none',
      },
    },
  };
}

// Styles from radio-wrapper
function getRadioBasicStyle(prefixCls: string, token: RadioToken): CSSInterpolation {
  const radioInnerPrefixCls = `${prefixCls}-inner`;

  return {
    [`.${prefixCls}-wrapper`]: {
      ...resetComponent(token),
      position: 'relative',
      display: 'inline-flex',
      alignItems: 'baseline',
      marginInlineStart: 0,
      marginInlineEnd: token.radioWrapperMarginRight,
      cursor: 'pointer',

      // RTL
      '&&-rtl': {
        direction: 'rtl',
      },

      '&-disabled': {
        cursor: 'not-allowed',
      },

      '&::after': {
        display: 'inline-block',
        width: 0,
        overflow: 'hidden',
        content: '"\\a0"',
      },

      // hashId 在 wrapper 上，只能铺平
      [`.${prefixCls}-checked::after`]: {
        position: 'absolute',
        insetBlockStart: 0,
        insetInlineStart: 0,
        width: '100%',
        height: '100%',
        border: `1px solid ${token.radioDotColor}`,
        borderRadius: '50%',
        visibility: 'hidden',
        animationName: antRadioEffect,
        animationDuration: '0.36s',
        animationTimingFunction: 'ease-in-out',
        animationFillMode: 'both',
        content: '""',
      },

      [`.${prefixCls}`]: {
        ...resetComponent(token),
        position: 'relative',
        insetBlockStart: token.radioTop,
        display: 'inline-block',
        outline: 'none',
        cursor: 'pointer',
      },

      [`.${prefixCls}-wrapper:hover &,
              &:hover .${radioInnerPrefixCls},
              &-input:focus + .${radioInnerPrefixCls}`]: {
        borderColor: token.radioDotColor,
      },

      [`.${prefixCls}-input:focus + .${radioInnerPrefixCls}`]: {
        boxShadow: token.radioFocusShadow,
      },

      [`.${prefixCls}:hover::after, .${prefixCls}-wrapper:hover &::after`]: {
        visibility: 'visible',
      },

      [`.${prefixCls}-inner`]: {
        '&::after': {
          position: 'absolute',
          insetBlockStart: '50%',
          insetInlineStart: '50%',
          display: 'block',
          width: token.radioSize,
          height: token.radioSize,
          marginBlockStart: token.radioSize / -2,
          marginInlineStart: token.radioSize / -2,
          backgroundColor: token.radioDotColor,
          borderBlockStart: 0,
          borderInlineStart: 0,
          borderRadius: token.radioSize,
          transform: 'scale(0)',
          opacity: 0,
          transition: `all ${token.motionDurationSlow} ${token.motionEaseInOutCirc}`,
          content: '""',
        },

        position: 'relative',
        insetBlockStart: 0,
        insetInlineStart: 0,
        display: 'block',
        width: token.radioSize,
        height: token.radioSize,
        backgroundColor: token.radioButtonBg,
        borderColor: token.colorBorder,
        borderStyle: 'solid',
        borderWidth: token.controlLineWidth,
        borderRadius: '50%',
        transition: `all ${token.motionDurationSlow}`,
      },

      [`.${prefixCls}-input`]: {
        position: 'absolute',
        insetBlockStart: 0,
        insetInlineEnd: 0,
        insetBlockEnd: 0,
        insetInlineStart: 0,
        zIndex: 1,
        cursor: 'pointer',
        opacity: 0,
      },

      // 选中状态
      [`.${prefixCls}-checked`]: {
        [`.${radioInnerPrefixCls}`]: {
          borderColor: token.radioDotColor,

          '&::after': {
            transform: `scale(${token.radioDotSize / token.radioSize})`,
            opacity: 1,
            transition: `all ${token.motionDurationSlow} ${token.motionEaseInOutCirc}`,
          },
        },
      },

      [`.${prefixCls}-disabled`]: {
        cursor: 'not-allowed',

        [`.${radioInnerPrefixCls}`]: {
          backgroundColor: token.colorBgComponentDisabled,
          borderColor: `${token.colorBorder} !important`,
          cursor: 'not-allowed',

          '&::after': {
            backgroundColor: token.radioDotDisabledColor,
          },
        },

        '&-input': {
          cursor: 'not-allowed',
        },

        [`.${prefixCls}-disabled + span`]: {
          color: token.colorTextDisabled,
          cursor: 'not-allowed',
        },
      },

      [`span.${prefixCls} + *`]: {
        paddingInlineStart: token.paddingXS,
        paddingInlineEnd: token.paddingXS,
      },
    },
  };
}

// Styles from radio-button
function getRadioButtonStyle(prefixCls: string, token: RadioToken): CSSInterpolation {
  return {
    [`.${prefixCls}-button-wrapper`]: {
      position: 'relative',
      display: 'inline-block',
      height: token.controlHeight,
      margin: 0,
      paddingInline: token.radioButtonPaddingHorizontal,
      paddingBlock: 0,
      color: token.radioButtonColor,
      fontSize: token.fontSize,
      lineHeight: `${token.controlHeight - token.controlLineWidth * 2}px`,
      background: token.radioButtonBg,
      border: `${token.controlLineWidth}px ${token.controlLineType} ${token.colorBorder}`,
      // strange align fix for chrome but works
      // https://gw.alipayobjects.com/zos/rmsportal/VFTfKXJuogBAXcvfAUWJ.gif
      borderBlockStartWidth: token.controlLineWidth + 0.02,
      borderInlineStartWidth: 0,
      borderInlineEndWidth: token.controlLineWidth,
      cursor: 'pointer',
      transition: `color ${token.motionDurationSlow}, background ${token.motionDurationSlow}, border-color ${token.motionDurationSlow}, box-shadow ${token.motionDurationSlow}`,

      a: {
        color: token.radioButtonColor,
      },

      [`> .${prefixCls}-button`]: {
        position: 'absolute',
        insetBlockStart: 0,
        insetInlineStart: 0,
        zIndex: -1,
        width: '100%',
        height: '100%',
      },

      [`.${prefixCls}-group-large &`]: {
        height: token.controlHeightLG,
        fontSize: token.fontSizeLG,
        lineHeight: `${token.controlHeightLG - token.controlLineWidth * 2}px`,
      },

      [`.${prefixCls}-group-small &`]: {
        height: token.controlHeightSM,
        paddingInline: token.paddingXS - token.controlLineWidth,
        paddingBlock: 0,
        lineHeight: `${token.controlHeightSM - token.controlLineWidth * 2}px`,
      },

      '&:not(:first-child)': {
        '&::before': {
          position: 'absolute',
          insetBlockStart: -token.controlLineWidth,
          insetInlineStart: -token.controlLineWidth,
          display: 'block',
          boxSizing: 'content-box',
          width: 1,
          height: '100%',
          paddingBlock: token.controlLineWidth,
          paddingInline: 0,
          backgroundColor: token.colorBorder,
          transition: `background-color ${token.motionDurationSlow}`,
          content: '""',
        },
      },

      '&:first-child': {
        borderInlineStart: `${token.controlLineWidth}px ${token.controlLineType} ${token.colorBorder}`,
        borderStartStartRadius: token.controlRadius,
        borderEndStartRadius: token.controlRadius,
      },

      '&:last-child': {
        borderStartEndRadius: token.controlRadius,
        borderEndEndRadius: token.controlRadius,
      },

      '&:first-child:last-child': {
        borderRadius: token.controlRadius,
      },

      '&:hover': {
        position: 'relative',
        color: token.radioDotColor,
      },

      '&:focus-within': {
        boxShadow: token.radioButtonFocusShadow,
      },

      [`.${prefixCls}-inner, input[type='checkbox'], input[type='radio']`]: {
        width: 0,
        height: 0,
        opacity: 0,
        pointerEvents: 'none',
      },

      '&-checked:not(&-disabled)': {
        zIndex: 1,
        color: token.radioDotColor,
        background: token.radioButtonCheckedBg,
        borderColor: token.radioDotColor,

        '&::before': {
          backgroundColor: token.radioDotColor,
        },

        '&:first-child': {
          borderColor: token.radioDotColor,
        },

        '&:hover': {
          color: token.radioButtonHoverColor,
          borderColor: token.radioButtonHoverColor,

          '&::before': {
            backgroundColor: token.radioButtonHoverColor,
          },
        },

        '&:active': {
          color: token.radioButtonActiveColor,
          borderColor: token.radioButtonActiveColor,

          '&::before': {
            backgroundColor: token.radioButtonActiveColor,
          },
        },

        '&:focus-within': {
          boxShadow: token.radioButtonFocusShadow,
        },
      },

      [`.${prefixCls}-group-solid &-checked:not(&-disabled)`]: {
        color: token.radioSolidCheckedColor,
        background: token.radioDotColor,
        borderColor: token.radioDotColor,

        '&:hover': {
          color: token.radioSolidCheckedColor,
          background: token.radioButtonHoverColor,
          borderColor: token.radioButtonHoverColor,
        },

        '&:active': {
          color: token.radioSolidCheckedColor,
          background: token.radioButtonActiveColor,
          borderColor: token.radioButtonActiveColor,
        },

        '&:focus-within': {
          boxShadow: token.radioButtonFocusShadow,
        },
      },

      '&-disabled': {
        color: token.colorTextDisabled,
        backgroundColor: token.colorBgComponentDisabled,
        borderColor: token.colorBorder,
        cursor: 'not-allowed',

        '&:first-child, &:hover': {
          color: token.colorTextDisabled,
          backgroundColor: token.colorBgComponentDisabled,
          borderColor: token.colorBorder,
        },
      },

      '&-disabled&-checked': {
        color: token.radioDisabledButtonCheckedColor,
        backgroundColor: token.radioDisabledButtonCheckedBg,
        borderColor: token.colorBorder,
        boxShadow: 'none',
      },
    },
  };
}

// ============================== Export ==============================
export function getStyle(
  prefixCls: string,
  antPrefix: string,
  token: RadioToken,
): CSSInterpolation {
  return [
    getGroupRadioStyle(prefixCls, antPrefix, token),
    getRadioBasicStyle(prefixCls, token),
    getRadioButtonStyle(prefixCls, token),
  ];
}

export default function useStyle(prefixCls: string, antPrefix: string): UseComponentStyleResult {
  const [theme, token, hashId] = useToken();
  return [
    useStyleRegister({ theme, token, hashId, path: [prefixCls] }, () => {
      const radioToken = getRadioToken(token);
      return getStyle(prefixCls, antPrefix, radioToken);
    }),
    hashId,
  ];
}
