import React, { useState, useRef } from 'react';
import { BaseRating, IconContainer } from '@epam/uui-components';
import { Icon, IEditable, IHasRawProps } from '@epam/uui-core';
import css from './SliderRating.module.scss';
import { ReactComponent as LineGrayIcon } from '../icons/slider-rating/line_gray_icon.svg';
import { ReactComponent as LineRedIcon } from '../icons/slider-rating/line_red_icon.svg';
import { ReactComponent as LineYellowIcon } from '../icons/slider-rating/line_yellow_icon.svg';
import { ReactComponent as LineBlueIcon } from '../icons/slider-rating/line_blue_icon.svg';
import { ReactComponent as LineVioletIcon } from '../icons/slider-rating/line_violet_icon.svg';
import { ReactComponent as ActiveMarkRedIcon } from '../icons/slider-rating/active_mark_red_icon.svg';
import { ReactComponent as ActiveMarkYellowIcon } from '../icons/slider-rating/active_mark_yellow_icon.svg';
import { ReactComponent as ActiveMarkGreenIcon } from '../icons/slider-rating/active_mark_green_icon.svg';
import { ReactComponent as ActiveMarkBlueIcon } from '../icons/slider-rating/active_mark_blue_icon.svg';
import { ReactComponent as ActiveMarkVioletIcon } from '../icons/slider-rating/active_mark_violet_icon.svg';
import { ReactComponent as NaIcon } from '../icons/slider-rating/na_icon.svg';
import { ReactComponent as NaActiveIcon } from '../icons/slider-rating/na_active_icon.svg';
import { Tooltip } from '../overlays';
import cx from 'classnames';
import { i18n } from '../../i18n';

const defaultSize = '18';

export interface SliderRatingProps<TValue> extends IEditable<TValue>, IHasRawProps<React.HTMLAttributes<HTMLDivElement>> {
    renderTooltip?: (value: TValue) => React.ReactNode;
    from?: 1 | 2;
    withoutNa?: boolean;
    size?: '18' | '24';
    getScaleIcon?: (value: number) => Icon;
    getHandlerIcon?: (value: number) => Icon;
}

const maxValue = 5;

export class SliderRating extends React.Component<SliderRatingProps<number>> {
    handlerWidth: number;
    getScaleIcon = (rating: number) => {
        switch (rating) {
            case 1:
                return LineRedIcon;
            case 2:
                return LineYellowIcon;
            case 3:
                return LineGrayIcon;
            case 4:
                return LineBlueIcon;
            case 5:
                return LineVioletIcon;
            default:
                return LineGrayIcon;
        }
    };

    getHandlerIcon = (rating: number) => {
        switch (rating) {
            case 1:
                return ActiveMarkRedIcon;
            case 2:
                return ActiveMarkYellowIcon;
            case 3:
                return ActiveMarkGreenIcon;
            case 4:
                return ActiveMarkBlueIcon;
            case 5:
                return ActiveMarkVioletIcon;
        }
    };

    getLeftHandlerIconPosition = (rating: number, from: number, stepWidth: number) => {
        const left = !!rating ? (rating - from) * stepWidth - this.handlerWidth / 2 : 0;

        if (rating && rating === from) {
            return left + 2;
        } else if (rating && rating === maxValue) {
            return left - 2;
        }

        return left;
    };

    renderTooltipBox(rating: number) {
        const tooltipContent = this.props.renderTooltip ? this.props.renderTooltip(rating) : `${rating}`;
        return <TooltipBox content={ tooltipContent } size={ this.props.size || '18' } />;
    }

    renderRating = (sliderRating: number, markWidth: number, numberOfMarks: number) => {
        const rating = sliderRating || 0;
        const from = this.props.from || 1;
        const stepWidth = (markWidth * numberOfMarks) / (numberOfMarks - 1);
        const left = this.getLeftHandlerIconPosition(rating, from, stepWidth);
        const size = this.props.size || defaultSize;

        return (
            <>
                <div className={ cx(css.scale, css[`size-${size}`], from === 2 && css.shortScale) }>
                    <IconContainer cx={ css.scaleIcon } icon={ this.props.getScaleIcon ? this.props.getScaleIcon(rating) : this.getScaleIcon(rating) } />
                </div>
                {this.renderTooltipBox(rating)}
                <div
                    className={ cx(css.handler, css[`size-${size}`], !rating && css.hidden) }
                    style={ { left: left } }
                    ref={ (handler) => {
                        this.handlerWidth = handler && handler.offsetWidth;
                    } }
                >
                    <Tooltip cx={ css.tooltip } content={ this.props.renderTooltip ? this.props.renderTooltip(rating) : `${rating}` }>
                        <IconContainer cx={ css.handlerIcon } icon={ this.props.getHandlerIcon ? this.props.getHandlerIcon(rating) : this.getHandlerIcon(rating) } />
                    </Tooltip>
                </div>
            </>
        );
    };

    renderNa() {
        const isReadonly = this.props.isReadonly || this.props.isDisabled;
        const size = this.props.size || defaultSize;

        if (isReadonly && this.props.value !== 0) {
            return <IconContainer cx={ cx(css.naIcon, css[`size-${size}`], css.disabled) } icon={ NaIcon } />;
        } else {
            return (
                <Tooltip content={ this.props.renderTooltip ? this.props.renderTooltip(0) : i18n.sliderRating.notAvailableMessage }>
                    <IconContainer
                        cx={ cx(css.naIcon, css[`size-${size}`], isReadonly && css.disabled) }
                        icon={ this.props.value === 0 ? NaActiveIcon : NaIcon }
                        onClick={ !isReadonly && (() => this.props.onValueChange(0)) }
                    />
                </Tooltip>
            );
        }
    }

    render() {
        return (
            <div className={ css.container } { ...this.props.rawProps }>
                <BaseRating
                    from={ this.props.from || 1 }
                    to={ maxValue }
                    step={ 1 }
                    renderRating={ this.renderRating }
                    { ...this.props }
                    value={ this.props.value === 0 ? null : this.props.value }
                    cx={ css.baseRatingContainer }
                />
                {!this.props.withoutNa && <div className={ css.naIconContainer }>{this.renderNa()}</div>}
            </div>
        );
    }
}

type TooltipBoxProps = {
    size: string;
    content: React.ReactNode | string;
};

function TooltipBox(props: TooltipBoxProps) {
    const { content, size } = props;
    const tooltipBoxRef = useRef<HTMLDivElement>(null);
    const [left, setLeft] = useState<number>(0);

    const topPosition = tooltipBoxRef.current?.getBoundingClientRect().y || 0;

    return (
        <div className={ css.tooltipsBox } ref={ tooltipBoxRef } onMouseMove={ (event: React.MouseEvent) => setLeft(event.clientX) }>
            <Tooltip placement="top" content={ content } cx={ css.tooltip }>
                <div
                    className={ css.tooltipsBoxItem }
                    style={ {
                        left: `${left - 1}px`,
                        top: `${topPosition}px`,
                        height: `${size}px`,
                    } }
                />
            </Tooltip>
            <Tooltip placement="top" content={ content } cx={ css.tooltip }>
                <div
                    className={ css.tooltipsBoxItem }
                    style={ {
                        left: `${left}px`,
                        top: `${topPosition}px`,
                        height: `${size}px`,
                    } }
                />
            </Tooltip>
            <Tooltip placement="top" content={ content } cx={ css.tooltip }>
                <div
                    className={ css.tooltipsBoxItem }
                    style={ {
                        left: `${left + 1}px`,
                        top: `${topPosition}px`,
                        height: `${size}px`,
                    } }
                />
            </Tooltip>
        </div>
    );
}
