// Copyright 2023 The Casdoor Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/** @jsxImportSource @emotion/react */

import {Input, Popover, Space, theme} from "antd";
import React, {useEffect, useMemo, useRef, useState} from "react";
import {css} from "@emotion/react";
import i18next from "i18next";
import {TinyColor} from "@ctrl/tinycolor";
import ColorPanel from "antd-token-previewer/es/ColorPanel";

export const BLUE_COLOR = "#1677FF";
export const PINK_COLOR = "#ED4192";
export const GREEN_COLOR = "#00B96B";

export const COLORS = [
  {
    color: BLUE_COLOR,
  },
  {
    color: "#5734d3",
  },
  {
    color: "#9E339F",
  },
  {
    color: PINK_COLOR,
  },
  {
    color: "#E0282E",
  },
  {
    color: "#F4801A",
  },
  {
    color: "#F2BD27",
  },
  {
    color: GREEN_COLOR,
  },
];

export const PRESET_COLORS = COLORS.map(({color}) => color);

const {useToken} = theme;

const useStyle = () => {
  const {token} = useToken();
  return {
    color: css `
      width: ${token.controlHeightLG / 2}px;
      height: ${token.controlHeightLG / 2}px;
      border-radius: 100%;
      cursor: pointer;
      transition: all ${token.motionDurationFast};
      display: inline-block;

      & > input[type="radio"] {
        width: 0;
        height: 0;
        opacity: 0;
      }
    `,
    colorActive: css `
      box-shadow: 0 0 0 1px ${token.colorBgContainer},
        0 0 0 ${token.controlOutlineWidth * 2 + 1}px ${token.colorPrimary};
    `,
  };
};

const DebouncedColorPanel = ({color, onChange}) => {
  const [value, setValue] = useState(color);
  const skipInitialDebounce = useRef(true);
  const onChangeRef = useRef(onChange);
  onChangeRef.current = onChange;

  useEffect(() => {
    setValue(color);
  }, [color]);

  useEffect(() => {
    if (skipInitialDebounce.current) {
      skipInitialDebounce.current = false;
      return;
    }
    const timeout = setTimeout(() => {
      onChangeRef.current?.(value);
    }, 200);
    return () => clearTimeout(timeout);
  }, [value]);

  return <ColorPanel color={value} onChange={setValue} />;
};

export default function ColorPicker({value, onChange}) {
  const style = useStyle();

  const matchColors = useMemo(() => {
    const valueStr = new TinyColor(value).toRgbString();
    let existActive = false;

    const colors = PRESET_COLORS.map((color) => {
      const colorStr = new TinyColor(color).toRgbString();
      const active = colorStr === valueStr;
      existActive = existActive || active;

      return {color, active, picker: false};
    });

    return [
      ...colors,
      {
        color: "conic-gradient(red, yellow, lime, aqua, blue, magenta, red)",
        picker: true,
        active: !existActive,
      },
    ];
  }, [value]);

  return (
    <Space size="large">
      <Input
        value={value}
        onChange={(event) => {
          onChange?.(event.target.value);
        }}
        style={{width: 120}}
      />
      <Space size="middle">
        {matchColors.map(({color, active, picker}) => {
          if (picker) {
            return (
              <Popover
                key="custom-color-picker"
                overlayInnerStyle={{padding: 0}}
                content={
                  <DebouncedColorPanel color={value || BLUE_COLOR} onChange={(c) => onChange?.(c)} />
                }
                trigger="click"
                showArrow={false}
              >
                <span
                  css={[style.color, active && style.colorActive]}
                  style={{
                    background: color,
                  }}
                  role="button"
                  tabIndex={0}
                  aria-label={i18next.t("theme:Primary color")}
                  onKeyDown={(e) => {
                    if (e.key === "Enter" || e.key === " ") {
                      e.preventDefault();
                      e.currentTarget.click();
                    }
                  }}
                />
              </Popover>
            );
          }

          return (
            <label
              key={color}
              css={[style.color, active && style.colorActive]}
              style={{
                background: color,
              }}
              onClick={() => {
                onChange?.(color);
              }}
            >
              <input type="radio" name="color" tabIndex={0} />
            </label>
          );
        })}
      </Space>
    </Space>
  );
}
