import "../../style/controls/contrastRatio.scss";

import { useMemo } from "react";

import { A11yNotice } from "./notice.js";
import { useA11yDispatcher } from "../../hooks/useA11yDispatcher.js";
import { useCustomizeValues } from "../../hooks/useCustomizeValues.js";
import { getSidebarCustomize } from "../../sidebar/getSidebarCustomize.js";
import { getLuminosityRatio } from "../../utils/getLuminosityRatio.js";
import { __ } from "../../utils/i18n.js";

import type { ComponentProps, FC, ReactNode } from "react";

const A11yContrastRatio: FC<{
    /**
     * List of setting IDs. The first two needs to be the settings which expose a
     * color. All other settings are useful for `modifier`.
     *
     * This property does not listen to changes of the array and is used one-time.
     */
    settings: string[];
    minimumRatio: number;
    severity: ComponentProps<typeof A11yNotice>["severity"];
    renderNotice?: (ratio: number, minimumRatio: number) => ReactNode;
    /**
     * Allows you to modify the value for the settings at runtime.
     */
    modifier?: (colors: [string, string], values: any[], getSetting: <T>(setting: string) => T) => [string, string];
}> = ({ settings, severity, minimumRatio, renderNotice, modifier }) => {
    const customize = getSidebarCustomize();
    const values = useCustomizeValues(settings);

    // Calculate luminosity ratio
    const ratio = useMemo(() => {
        const [color1, color2] = modifier
            ? modifier(
                  settings.slice(0, 2).reduce(
                      (p, c) => {
                          p.push(values[c].value);
                          return p;
                      },
                      [] as unknown as [string, string],
                  ),
                  settings.slice(2).reduce((p, c) => {
                      p.push(values[c].value);
                      return p;
                  }, [] as any[]),
                  (setting) => customize(setting).get(),
              )
            : [values[settings[0]].value as string, values[settings[1]].value as string];
        return getLuminosityRatio(color1, color2);
    }, [JSON.stringify(values)]);

    const renderedNotice = renderNotice?.(ratio, minimumRatio);
    const hasError = ratio < minimumRatio;

    useA11yDispatcher({
        setting: settings[1],
        valid: !hasError,
    });

    return (
        <>
            <strong>{__("Contrast ratio:")}</strong>&nbsp;
            {ratio.toFixed(2)}
            {hasError &&
                (renderedNotice ? (
                    <div
                        className={`notice notice-${severity} inline below-h2 notice-alt`}
                        style={{ margin: "10px 0" }}
                    >
                        <p>{renderedNotice}</p>
                    </div>
                ) : (
                    <A11yNotice
                        severity={severity}
                        text={__(
                            'We recommend a contrast ratio between background and font color of at least %f to comply with the {{aPerc}}"perceptibility" of the WCAG 2.2 standard{{/aPerc}} and thereby meet the {{aEuMinimum}}EU\'s minimum legal requirements for accessibility{{/aEuMinimum}}.',
                            minimumRatio,
                        )}
                    />
                ))}
        </>
    );
};

export { A11yContrastRatio };
