<template>
  <RenderLayout v-bind="props" />
</template>

<script lang="tsx" setup name="WidgetLjFoldLayout">
import { computed, onMounted, onUnmounted, ref, useSlots, watch, provide, withModifiers } from "vue";
import { ArrowLeft, ArrowRight, Right } from "@element-plus/icons-vue";
// import { useDesign } from "@/hooks/useDesign";
import LayoutAside, { type LjFoldLayoutAside } from "./components/LayoutAside.vue";
import { useLayoutLocalStore } from "@/stores/modules/layoutLocal";
// import { useI18n } from "vue-i18n";
import { defaultsDeep, cloneDeep, pick } from "lodash-es";
import mittBus from "@/utils/mittBus";
import { MittEnum } from "@/enums/mittEnum";
import { nextTick } from "vue";

/**
 * @description 默认设置
 */
const layoutAttrDefine: any = {
  left: {
    buttonType: "bar",
    minWidth: "unset",
    maxWidth: "unset",
    width: 20,
    autoHideWidth: 5,
    hidden: false
  },
  right: {
    buttonType: "bar",
    minWidth: "unset",
    maxWidth: "unset",
    width: 20,
    autoHideWidth: 5,
    hidden: false
  }
};
const layoutAttr = ["width", "hidden", "lastWidth"];
/**
 * @description 默认分割宽度
 */
const lineWidth = 8;
/**
 * @description 默认宽度 %
 */
const DEFAULT_WIDTH = 20;
/**
 * @description 默认自动隐藏距离
 */
const DEFAULT_HIDDEN_WIDTH = 5;
// const { prefixCls } = useDesign("fold-layout");
const prefixCls = "longjoe-fold-layout";
const asideWidth = ref();
const asideWidth_hide = ref();
const asideWidth_last = ref();
const asideWidth_r = ref();
const asideWidth_r_hide = ref();
const asideWidth_r_last = ref();
const emit = defineEmits(["foldLeft", "foldRight"]);

const getUnit = (value: number | string) => {
  let matches = value.toString().match(/([^0-9]+)[0-9]*$/);
  return matches ? matches[1] : "px";
};

const getNumber = (value: number | string) => {
  let matches = value.toString().match(/\d+/);
  return matches ? Number(matches[0]) : 0;
};
/**
 * @description %/px => px
 * @param percent
 */
const getWidthPx = (percent: string | number) => {
  let value;
  let unit = getUnit(percent);
  let _num = getNumber(percent);
  console.log("_num, layoutSize.value ==>", _num, layoutSize.value);
  if (unit == "px") {
    value = _num;
  } else {
    value = (_num * layoutSize.value) / 100;
  }
  return value;
};
/**
 * @description px => %
 * @param pxqty
 */
const changeUnitValue = (pxqty: number) => {
  return Number(((pxqty / layoutSize.value) * 100).toFixed(2));
};

// const { t } = useI18n();
const layoutLocalStore = useLayoutLocalStore();

export interface curLayoutTypeItem {
  /**
   * @argument {number} 当前宽度，%
   */
  width: number;
  /**
   * @argument {boolean} 是否隐藏模块
   */
  hidden?: boolean;
  /**
   * @argument {boolean} 是否折叠模块
   */
  collapse?: boolean;
  /**
   * @argument {number} 折叠后，记录上一次宽度 %
   */
  lastWidth?: number;
  // /**
  //  * @argument string 单位
  //  */
  // unit?: string;
}
interface curLayoutType {
  left: curLayoutTypeItem;
  right: curLayoutTypeItem;
}

interface LjFoldLayoutProps {
  left?: LjFoldLayoutAside | any;
  right?: LjFoldLayoutAside | any;
  /**
   * @description 布局名称，取值建议，主表布局名称，自动补充“__layout”
   */
  dwname?: string;
  /**
   * @description 方向：水平，垂直
   */
  direction?: "horizontal" | "vertical" | string;
  /**
   * @description 主体内容class类名
   */
  mainClass?: string;
}

const props = withDefaults(defineProps<LjFoldLayoutProps>(), {
  left: () => ({}),
  right: () => ({}),
  direction: "horizontal",
  mainClass: ""
});
console.log("props!!!!!!!!!!! :>> ", props);

/**
 * @description 记录当前状态属性,
 */
const currentLayout = ref<any>({});

const ljFoldLayoutRef = ref();
const dir = computed(() => (props.direction === "horizontal" ? "width" : "height"));
const slots = useSlots();
const layoutSize = ref<any>();
/**
 * @description 获取模块信息
 */
const getLayoutSize = () => {
  if (!ljFoldLayoutRef.value) {
    return 0;
  }
  let layout = ljFoldLayoutRef.value.getBoundingClientRect();
  return layout[dir.value];
};
const dwnameLayout = computed(() => {
  return props.dwname + "__layout";
});

provide("currentLayout", currentLayout);

const bindDropLeft = (e: any) => {
  if (asideWidth.value > 0) {
    asideWidth_last.value = asideWidth.value;
  }
  document.onmousemove = function (e) {
    if (props.left.minWidth === "unset") {
      if (props.direction == "horizontal") {
        asideWidth.value += e.movementX;
      } else {
        asideWidth.value += e.movementY;
      }
      if (asideWidth.value < asideWidth_hide.value) {
        asideWidth.value = 0;
      }
    } else {
      let _minSize = getNumber(props.left.minWidth ?? "");
      if (props.direction == "horizontal") {
        asideWidth.value += e.movementX;
      } else {
        asideWidth.value += e.movementY;
      }
      if (asideWidth.value <= _minSize) {
        asideWidth.value = _minSize;
      }
    }
  };
  document.onmouseup = function () {
    document.onmousemove = null;
    document.onmouseup = null;

    // 保存布局
    let limitSize = props.left.minWidth !== "unset" ? getWidthPx(props.left.minWidth ?? 0) : 0;
    let saveWidth = asideWidth.value <= limitSize ? 0 : asideWidth.value;
    setLayout({ left: { width: changeUnitValue(saveWidth) } });
  };
  return false;
};
const bindDropRight = (e: any) => {
  if (asideWidth_r.value > 0) {
    asideWidth_r_last.value = asideWidth_r.value;
  }
  document.onmousemove = function (e) {
    if (props.right.minWidth === "unset") {
      if (props.direction == "horizontal") {
        asideWidth_r.value -= e.movementX;
      } else {
        asideWidth_r.value -= e.movementY;
      }
      if (asideWidth_r.value < asideWidth_r_hide.value) {
        asideWidth_r.value = 0;
      }
    } else {
      let _minSize = getNumber(props.right.minWidth ?? "");
      if (props.direction == "horizontal") {
        asideWidth_r.value -= e.movementX;
      } else {
        asideWidth_r.value -= e.movementY;
      }
      if (asideWidth_r.value <= _minSize) {
        asideWidth_r.value = _minSize;
      }
    }
  };
  document.onmouseup = function () {
    document.onmousemove = null;
    document.onmouseup = null;

    // 保存布局
    let limitSize = props.right.minWidth !== "unset" ? getWidthPx(props.right.minWidth ?? 0) : 0;
    let saveWidth = asideWidth_r.value <= limitSize ? 0 : asideWidth_r.value;
    setLayout({ right: { width: changeUnitValue(saveWidth) } });
  };
  return false;
};
// 折叠事件
const foldLeft = () => {
  let limitSize = props.left.minWidth !== "unset" ? getWidthPx(props.left.minWidth ?? 0) : 0;
  if (asideWidth.value > limitSize) {
    asideWidth_last.value = asideWidth.value;
  }

  if (asideWidth.value === limitSize || asideWidth.value <= limitSize) {
    if (asideWidth_last.value && asideWidth_last.value > 0) {
      asideWidth.value = asideWidth_last.value;
      asideWidth_last.value = 0;
    } else {
      asideWidth.value = changeUnitValue(DEFAULT_WIDTH);
    }
  } else {
    asideWidth.value = limitSize;
  }

  let saveWidth = asideWidth.value === limitSize ? 0 : asideWidth.value;
  setLayout({
    left: { width: changeUnitValue(saveWidth), lastWidth: changeUnitValue(asideWidth_last.value ?? 0) }
  });
};

const foldRight = () => {
  let limitSize = props.right.minWidth !== "unset" ? getWidthPx(props.right.minWidth ?? 0) : 0;
  if (asideWidth_r.value > limitSize) {
    asideWidth_r_last.value = asideWidth_r.value;
  }
  // console.log("asideWidth_r.value :>> ", asideWidth_r.value);
  // console.log("limitSize :>> ", limitSize);
  // console.log("asideWidth_r.value <= limitSize :>> ", asideWidth_r.value <= limitSize);
  // console.log("asideWidth_r_last.value :>> ", asideWidth_r_last.value);
  // console.log('getWidthPx(asideWidth_r_last + "%") :>> ', getWidthPx(asideWidth_r_last.value + "%"));
  if (asideWidth_r.value === 0 || asideWidth_r.value <= limitSize) {
    if (asideWidth_r_last.value && asideWidth_r_last.value > 0) {
      asideWidth_r.value = asideWidth_r_last.value;
      asideWidth_r_last.value = 0;
    } else {
      asideWidth_r.value = changeUnitValue(DEFAULT_WIDTH);
    }
  } else {
    asideWidth_r.value = limitSize;
  }

  let saveWidth = asideWidth_r.value === limitSize ? 0 : asideWidth_r.value;
  setLayout({
    right: { width: changeUnitValue(saveWidth), lastWidth: changeUnitValue(asideWidth_r_last.value ?? 0) }
  });
};

/**
 * @description 初始化，基础信息
 */
const init = () => {
  layoutSize.value = getLayoutSize();
  console.log("currentLayout.value :>> ", currentLayout.value);
  if (slots.left) {
    let _width = getWidthPx(currentLayout.value.left?.width + "%");
    // let _width =
    //   currentLayout.value.left.lastWidth && currentLayout.value.left.lastWidth > 0 ? 0 : currentLayout.value.left?.width;
    let limitSize = props.left.minWidth !== "unset" ? getWidthPx(props.left.minWidth ?? 0) : 0;
    if (limitSize > 0 && _width < limitSize) {
      asideWidth.value = limitSize;
    } else {
      asideWidth.value = _width;
    }
    currentLayout.value.left.lastWidth &&
      currentLayout.value.left.lastWidth > 0 &&
      (asideWidth_last.value = getWidthPx(currentLayout.value.left.lastWidth + "%"));
    asideWidth_hide.value = getWidthPx(props.left?.autoHideWidth ?? DEFAULT_HIDDEN_WIDTH);
  }
  if (slots.right) {
    let _width = getWidthPx(currentLayout.value.right?.width + "%");
    console.log("currentLayout.value.right?.width :>> ", currentLayout.value.right?.width);
    // let _width =
    //   currentLayout.value.right.lastWidth && currentLayout.value.right.lastWidth > 0 ? 0 : currentLayout.value.right?.width;
    let limitSize = props.right.minWidth !== "unset" ? getWidthPx(props.right.minWidth ?? 0) : 0;
    console.log("limitSize :>> ", limitSize);
    console.log("_width :>> ", _width);
    console.log("_width < limitSize :>> ", _width < limitSize);
    if (limitSize > 0 && _width < limitSize) {
      asideWidth_r.value = limitSize;
    } else {
      asideWidth_r.value = _width;
    }
    currentLayout.value.right.lastWidth &&
      currentLayout.value.right.lastWidth > 0 &&
      (asideWidth_r_last.value = getWidthPx(currentLayout.value.right.lastWidth + "%"));
    asideWidth_r_hide.value = getWidthPx(props.right?.autoHideWidth ?? DEFAULT_HIDDEN_WIDTH);

    console.log("asideWidth_r.value :>> ", asideWidth_r.value);
    console.log("asideWidth_r_last.value :>> ", asideWidth_r_last.value);
  }
};

/**
 * 逻辑：精简出与默认数据不同的属性，保留layoutAttr包含的字段
 * @param data 对象数据
 * @param {String[]} layoutAttr 需要保留的数据名称
 * @param {Object} layoutDefine 数据默认值 {...}
 */
const streamlineFunc = (data: any, layoutAttr: string[], layoutDefine: any) => {
  let saveCol: any = {};
  for (let key in data) {
    let saveProp = cloneDeep(layoutAttr);
    for (let attr in layoutDefine[key]) {
      if (data[key].hasOwnProperty(attr) && layoutDefine[key][attr] === data[key][attr]) {
        saveProp.indexOf(attr) > -1 && saveProp.splice(saveProp.indexOf(attr), 1);
      }
    }
    let _save = pick(data[key], saveProp);
    Object.keys(_save).length > 0 && (saveCol[key] = _save);
  }

  return saveCol;
};

/**
 * @description 设置布局, 储存使用百分比，渲染使px
 */
const setLayout = async (value: any) => {
  // if (!props.dwname) return Promise.resolve();
  let _val = cloneDeep(value);
  let layout = defaultsDeep(value, currentLayout.value);
  console.log("setLayout value:>> ", value);
  console.log("setLayout _val:>> ", _val);
  // 动态默认值
  let dynamicDefault = { ...layoutAttrDefine, ...{ left: props?.left }, ...{ right: props?.right } };
  let _layout = streamlineFunc(layout, layoutAttr, dynamicDefault);
  console.log("setLayout _layout :>> ", _layout, props.dwname);
  if (props.dwname) {
    // 保存布局，有设置dwname值，独立保存
    await layoutLocalStore.setDwLayout(dwnameLayout.value, _layout).then(() => {
      currentLayout.value = layout;

      mittBus.emit(MittEnum.FoldLayoutChange, layout);
    });
  } else {
    // 或者 通过emit返回
    if (_val.left) {
      emit("foldLeft", layout);
    } else if (_val.right) {
      emit("foldRight", layout);
    }
  }
};

/**
 * @description 切换：显示与隐藏
 * @param type 方向，left or right
 */
const toggleAside = (type: "left" | "right", callback: any) => {
  if (type == "left") {
    let bool = !currentLayout.value.left?.hidden;
    setLayout({ left: { hidden: bool } }).then(() => {
      callback && callback();
    });
  } else {
    let bool = !currentLayout.value.right?.hidden;
    setLayout({ right: { hidden: bool } }).then(() => {
      callback && callback();
    });
  }
};

/**
 * @description 当前布局
 */
const getLayout = async () => {
  if (!props.dwname) return Promise.resolve();
  let res: any = await layoutLocalStore.getLayoutAttr(dwnameLayout.value);
  console.log("getLayout res :>> ", JSON.stringify(res));

  /**只读取关键字段 */
  if (Object.keys(res).includes("left")) {
    res.left = pick(res.left, layoutAttr);
  }
  if (Object.keys(res).includes("right")) {
    res.right = pick(res.right, layoutAttr);
  }
  console.log("getLayout res pick :>> ", JSON.stringify(res));
  console.log("currentLayout.value res :>> ", currentLayout.value);

  currentLayout.value = defaultsDeep(res, currentLayout.value);
  console.log("currentLayout.value afff :>> ", currentLayout.value);
};

onMounted(() => {
  window.addEventListener("resize", init);

  getLayout().then(() => {
    init();
  });
});

onUnmounted(() => {
  window.removeEventListener("resize", init);
});

/**
 * @description Render：控制栏
 */
const RenderLineButton = (rProp: any) => {
  let _minWidth = rProp.type == "right" ? props.right.minWidth : props.left.minWidth;
  let limitSize = _minWidth !== "unset" ? getWidthPx(_minWidth ?? 0) : 0;
  let _className, _style, _icon, ifBar;
  let _cursor = dir.value == "width" ? "col-resize" : "row-resize";

  if (rProp.type == "right") {
    let isLimitSize = asideWidth_r.value === limitSize;
    _className = `${prefixCls}-line-bar ${isLimitSize ? "is-collapsed" : ""} ${rProp.type ?? ""} ${props.direction}`;
    _style = {
      cursor: isLimitSize ? "" : _cursor,
      [dir.value]: asideWidth_r.value === 0 ? 0 : lineWidth + "px"
    };
    _icon = isLimitSize ? ArrowLeft : ArrowRight;
    ifBar = props.right.buttonType;
  } else {
    let isLimitSize = asideWidth.value === limitSize;
    _className = `${prefixCls}-line-bar ${isLimitSize ? "is-collapsed" : ""} ${rProp.type ?? ""} ${props.direction}`;
    _style = { cursor: isLimitSize ? "" : _cursor, [dir.value]: asideWidth.value === 0 ? 0 : lineWidth + "px" };
    _icon = isLimitSize ? ArrowRight : ArrowLeft;
    ifBar = props.left.buttonType;
  }
  return (
    <>
      {
        <div class={`${prefixCls}-line`} style={_style}>
          <div class={`${prefixCls}-line-control ${props.direction}`} onMousedown={rProp.bindDrop}></div>
          {ifBar == "button" ? (
            <el-button icon={_icon} circle class={`${prefixCls}-line-button`} onClick={rProp.barclick}></el-button>
          ) : (
            <div class={_className} onClick={rProp.barclick}>
              <div class="top"></div>
              <div class="bottom"></div>
            </div>
          )}
        </div>
      }
    </>
  );
};

const RenderMain = () => {
  return <>{<div class={`${prefixCls}-main ${props.mainClass}`}>{slots.default?.({ layout: currentLayout.value })}</div>}</>;
};

const RenderLayout = (rProp: any) => {
  return (
    <>
      <div class={`${prefixCls} ${props.direction}`} ref={ljFoldLayoutRef}>
        {!currentLayout.value.left?.hidden && slots.left && (
          <LayoutAside {...rProp.left} width={asideWidth.value} styleAttr={dir.value}>
            {slots.left?.({ layout: currentLayout.value.left })}
          </LayoutAside>
        )}
        {!currentLayout.value.left?.hidden && slots.left && <RenderLineButton barclick={foldLeft} bindDrop={bindDropLeft} />}
        <RenderMain />
        {!currentLayout.value.right?.hidden && slots.right && (
          <RenderLineButton type="right" barclick={foldRight} bindDrop={bindDropRight} />
        )}
        {!currentLayout.value.right?.hidden && slots.right && (
          <LayoutAside {...rProp.right} width={asideWidth_r.value} styleAttr={dir.value}>
            {slots.right?.({ layout: currentLayout.value })}
          </LayoutAside>
        )}
      </div>
    </>
  );
};

watch(
  () => props,
  val => {
    currentLayout.value = defaultsDeep({ left: val.left ?? {}, right: val.right ?? {} }, layoutAttrDefine);
    console.log("watch props val :>> ", JSON.stringify(val));
    console.log("watch props val right:>> ", JSON.stringify(val.right));
    console.log("watch props currentLayout.value :>> ", currentLayout.value);
    nextTick(() => {
      init();
    });
  },
  { deep: true, immediate: true }
);

defineExpose({
  currentLayout,
  setLayout,
  getLayout,
  toggleAside,
  foldLeft,
  foldRight
});
</script>

<style lang="scss">
@import "./index.scss";
</style>
