import {
  Component, FunctionalComponent, h, useEffect, useEvent, useProp, useRef, useState,
} from "atomico";
import get from "lodash/get";
import { useStylesheet } from "@caedman/kit/dist/use-stylesheet";
import { Maybe } from "purify-ts/es/Maybe";
import "@caedman/gs/dist/global-style";
import style from "./kun-dropdown.scss";

import "../kun-icon/kun-icon";
import { getComponentOrDefine } from "../../hooks/aync-hook/redirect";

export function isChildOf(child: HTMLElement, parent: HTMLElement): boolean {
  return parent.contains(child);
}

interface Props<T> {
    value: T;
    options: T[];
}

const KunDropdown: FunctionalComponent = <T extends {}>(props: Props<T>) => {
  const [value, setValue] = useProp<T|undefined>("value");
  const [optionMapper] = useProp<string[]>("optionMapper");
  const [width] = useProp<number>("kunWidth");
  const [kunClass] = useProp<string>("kunClass");

  const optionMap = (txt: T): string => (optionMapper == null ? JSON.stringify(txt) : Maybe.encase(() => get(txt, optionMapper)).orDefault("请选择"));
  const [show, setShow] = useState(false);
  const renderString = (v: T): string => Maybe.fromFalsy(v).map(optionMap).orDefault("");

  const selectEvent = useEvent("MySelect", {
    composed: true,
    bubbles: true,
  });

  useEffect(() => {
    setValue(props.value);
  }, [props.value]);

  const ref = useRef<HTMLElement>();

  const clickEventI = (event: MouseEvent): void => {
    if (
      event.target != null
        && !isChildOf(event.target as HTMLElement, ref.current!)
    ) {
      if (show) {
        setShow(false);
        event.preventDefault();
      }
    }
  };

  useEffect(() => {
    document.addEventListener("click", clickEventI);
    return () => {
      document.removeEventListener("click", clickEventI);
    };
  }, [show]);

  const changeValue = (v: T, index: number, e: Event): void => {
    setValue(v);
    setShow(false);
    selectEvent(v);
    e.preventDefault();
  };

  const style1 = `
    .kun-dropdown-create {
      border-style: solid;
      border-color: black;
    }
    .select-input {
      line-height: 36px;
    }
    .kun-dropdown-button {
      width: ${width ?? 100}px;
    }
    .bubble {
      width: ${width ?? 100}px;
    }
  `;

  useStylesheet(style1, style);
  return (
    <host shadowDom>
      <div className={`kun-select ${kunClass ?? ""}`} ref={ref}>
        <button
          type="button"
          onclick={(e: MouseEvent) => {
            setShow(!show);
            e.preventDefault();
            e.stopPropagation();
          }}
          className=" kun-dropdown-button justify-between outline-none focus:outline-none inline-flex py-1 cursor-pointer px-2 rounded border border-gray-200 items-center "
        >
          <div className="mr-4 select-input"><span className="text-sm">{renderString(value)}</span></div>
          <kun-icon className={`flex-none ${!show ? "transform rotate-180" : ""}`} iconHeight="14" iconWidth="14" iconType="up" />
        </button>
        {
          show && (
          <div className="bubble flex flex-col">
            {
                  props.options.map((item, index) => (
                    <div
                      className="hover:bg-gray-200 cursor-pointer py-2 px-2"
                      key={String(item)}
                      onclick={(e) => changeValue(item, index, e)}
                    >
                      {renderString(item)}
                    </div>
                  ))
                }
          </div>
          )
        }
      </div>
      <global-style />
    </host>
  );
};

KunDropdown.props = {
  options: {
    type: Array,
  },
  kunClass: {
    type: String,
  },
  kunWidth: {
    type: Number,
  },
  optionMapper: {
    type: Array,
  },
  value: {
    type: Object,
  },
};

export default getComponentOrDefine("kun-dropdown", KunDropdown);
