import React from "react";
import { message, notification, Modal, Space, Button } from 'antd';
import { Redirect } from 'react-router-dom';
import { ExclamationCircleOutlined } from '@ant-design/icons';
import { Subject } from 'rxjs';
import LocalStorage from 'local-storage';

import { dispatchLatest, action } from '../model';
import { set_sess_state } from "../model/reducer";
import { DataModelerRoleAdmin, DataModelerRoleUser, DataModelerRoleReader, DataModelerRoleApproval } from './constant';

//内网深交所环境 isSzseEnv true
//元曜公网环境 isSzseEnv false
export const isSzseEnv = false;

export const inputWidth = isSzseEnv?360:240;

export const ContextPath = '/data-govern';
export const $hostParams = new Subject();

const routeMap = {};
export const ConvertToRouteMap = function (routes, pPath, pRoute) {

  routes.map((route, i) => {
    const { name, children, redirect } = route;
    const path = `${pPath ? pPath : ''}/${name}`;
    route.path = `${ContextPath}${path}`;
    route.parent = pRoute;
    if (redirect) {
      route.redirect = `${route.path}/${redirect}`;
    }
    if (!(route.path in routeMap)) {
      routeMap[route.path] = route;
    }
    children && ConvertToRouteMap(children, path, route);
    return route;
  });
  return routeMap;
}

export const RedirectHome = () => <Redirect to={`${ContextPath}/home`} />

export const RedirectSignin = () => <Redirect to={`${ContextPath}/login`} />

export const Open = function (url, args) { 
  const { target = '_blank' } = args || {};
  return window.open(url, target);//_self
}

export function Connect(modules) {
  const funcs = {};
  for (const m in modules) {
    const mdl = modules[m];
    for (const f in mdl) {
      const name = [m, f].join('.');
      funcs[name] = mdl[f];
    }
  }
  return funcs;
}

export class GetSession extends React.Component {
  componentDidMount() {
    const { history, location } = this.props;
    dispatchLatest({
      type: 'user.fetchSessionInfo',
      callback: session => {
        if (session && session.userId) {
          action({ type: set_sess_state, args: session })
        } else {
          action({ type: set_sess_state, args: { referer: location.pathname } })
          history.push(`${ContextPath}/login`);
        }
      },
      error: () => {
        action({ type: set_sess_state, args: { referer: location.pathname } })
        history.push(`${ContextPath}/login`);
      }
    })
  }
  render() {
    return <div>正在获取登录信息...</div>;
  }
}

export const Assert = function (arg, msg) {
  if (!arg) {
    this.showMessage('warn', msg);
    throw msg
  }
}

export class DeleteTipModal extends React.Component {

  render() {
    const { visible=false, tip, onCancel } = this.props;

    return <Modal 
      title=''
      visible={visible}
      closable={false}
      footer={null}
    >
      <div
        className='mt-3'
        style={{
          fontSize: '16px',
          fontWeight: 500,
          lineHeight: 1.4
        }}
      >
        <ExclamationCircleOutlined style={{ color: '#faad14' }} />
        <span className='ml-3'>{tip||''}</span>
      </div>
      <div className='flex mt-5' style={{ justifyContent: 'flex-end' }}>
        <Space>
          <Button onClick={() => onCancel()}>
            取消
          </Button>
          <Button type='primary' onClick={() => onCancel(true)}>
            确定
          </Button>
        </Space>
      </div>
    </Modal>
  }
}

export const paginate = function (items, pageNum = 1, pageSize = 10) {
  const offset = (pageNum - 1) * pageSize;
  return items?.filter((item, i) => i >= offset && i < offset + pageSize);
}

export const IsArr = function (data) {
  return data && Object.prototype.toString.call(data) === '[object Array]';
}

export const generateUUID = function() {
  let d = new Date().getTime();
  let uuid = 'xxxxxxxxxxxx4xxxyxxxxxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
    let r = (d + Math.random() * 16) % 16 | 0;
    d = Math.floor(d / 16);
    return (c === 'x' ? r : (r & 0x3) | 0x8).toString(16);
  });
  return uuid;
}

export const showMessage = function(action, content) {
  //https://github.com/ant-design/ant-design/issues/22269
  message.config({ prefixCls: "yy-message" });
  if (action === 'success') {
    message.success(content);
  }
  if (action === 'error') {
    message.error(content);
  }
  if (action === 'info') {
    message.info(content);
  }
  if (action === 'warn') {
    message.warn(content);
  }
}

export const showNotifaction = function(title, tip, duration=0) {

  notification.config({ prefixCls: "yy-notification" });
  notification.open({
    message: title||'提示',
    description: (typeof tip === 'string' ? (<span dangerouslySetInnerHTML={{ __html: tip||''}} />) : tip),
    duration: duration,
  });
} 

export const showErrorNotifaction = function(title, tip, duration=0) {

  notification.config({ prefixCls: "yy-notification" });
  notification.error({
    message: title||'提示',
    description: (typeof tip === 'string' ? (<span dangerouslySetInnerHTML={{ __html: tip||''}} />) : tip),
    duration: duration,
  });
} 

export function generateList(data,dataList){
  if(data[0]===undefined)
      return data
  for (let item of data){
      const { key,title } = item;
      dataList.push({ key, title });
      if (item.children) {
          dataList.concat(generateList(item.children,dataList))
      }
  }
  return dataList
};

export const getQueryParam = (param, url) => {
  //eslint-disable-next-line 
  const name = param.replace(/[\[\]]/g, '\\$&') 
  const regex = new RegExp('[?&]' + name + '(=([^&#]*)|&|#|$)')
  const results = regex.exec(url)
  if (!results) return null
  if (!results[2]) return ''
  return decodeURIComponent(results[2].replace(/\+/g, ' '))
}

function highlightSearchContent(content) {
  if (content===null || content==='') return '';

  const startFlag = '<em>';
  const endFlag = '</em>';

  const start = content.indexOf(startFlag);
  const end = content.indexOf(endFlag);
  const beforeStr = content.substr(0, start);

  const middleStr = content.substr(start + startFlag.length, end - start - startFlag.length);
  const afterStr = content.substr(end + endFlag.length);

  return (
    <>
    {
      start > -1 ? <span>
        {beforeStr}
        <span style={{ color: '#f50' }}>{middleStr}</span>
        {highlightSearchContent(afterStr)}
      </span> : <span>{content}</span>
    }
    </>
  )
}

export function searchContentAddDecorate(content, terms, matchCount=0) {

  if (!content || content==='') return '';
  if ((terms||[]).length===0 || typeof(content)!=='string') return content;
  if (matchCount >= 10) return content;

  let start = -1;
  let useTerm = '';
  terms.forEach(term => {
    const index = content.indexOf(term);

    if (index !== -1) {
      if (start === -1) {
        start = index;
        useTerm = term;
      } else if (index<start) {
        start = index;
        useTerm = term;
      }
    }
  })

  if (start > -1) {
    const beforeStr = content.substr(0, start);
    const middleStr = content.substr(start, useTerm.length);
    const afterStr = content.substr(start + useTerm.length);

    return `${beforeStr}<em>${middleStr}</em>${searchContentAddDecorate(afterStr, terms, ++matchCount)}`;
  }

  return content;
}

export function highlightSearchContentByTerms(content, terms) {
  if (!content || content==='') return '';
  if ((terms||[]).length===0 || typeof(content)!=='string') return content;

  let processContent = content;
  processContent = searchContentAddDecorate(processContent, terms);

  return highlightSearchContent(processContent);
}

export function highlightVersionChangeInformation(content) {
  if (content===null || content==='') return '';

  const startDeleteFlag = '<DD>';
  const endDeleteFlag = '</DD>';

  const startAddFlag = '<AA>';
  const endAddFlag = '</AA>';

  const startDelete = content.indexOf(startDeleteFlag);
  const endDelete = content.indexOf(endDeleteFlag);

  const startAdd = content.indexOf(startAddFlag);
  const endAdd = content.indexOf(endAddFlag);

  let start = -1, end = 0, startFlag = '', endFlag = '', isDelete = false;
  if (startDelete!==-1 && (startAdd===-1 || startDelete<startAdd)) {
    start = startDelete;
    end = endDelete;
    startFlag = startDeleteFlag;
    endFlag = endDeleteFlag;
    isDelete = true;
  } else if (startAdd!==-1 && (startDelete===-1 || startDelete>startAdd)) {
    start = startAdd;
    end = endAdd;
    startFlag = startAddFlag;
    endFlag = endAddFlag;
    isDelete = false;
  }

  const beforeStr = content.substr(0, start);

  const middleStr = content.substr(start + startFlag.length, end - start - startFlag.length);
  const afterStr = content.substr(end + endFlag.length);

  return (
    <>
    {
      start > -1 ? <span>
        {beforeStr}
        <span style={{ backgroundColor: isDelete?'#ffe7e7':'#ddfade', textDecoration: isDelete?'line-through':'' }}>{middleStr}</span>
        {highlightVersionChangeInformation(afterStr)}
      </span> : <span>{content}</span>
    }
    </>
  )
}

export function formatDate(t) {
  if (t === null) return '';

  var date = new Date(t);
  var YY = date.getFullYear() + '-';
  var MM = (date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1) + '-';
  var DD = (date.getDate() < 10 ? '0' + (date.getDate()) : date.getDate());
  var hh = (date.getHours() < 10 ? '0' + date.getHours() : date.getHours()) + ':';
  var mm = (date.getMinutes() < 10 ? '0' + date.getMinutes() : date.getMinutes()) + ':';
  var ss = (date.getSeconds() < 10 ? '0' + date.getSeconds() : date.getSeconds());
  return YY + MM + DD +" "+hh + mm + ss;
}

export function formatVersionDate(t) {
  if (t === null) return '';

  var date = new Date(t);
  var YY = date.getFullYear() + '-';
  var MM = (date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1) + '-';
  var DD = (date.getDate() < 10 ? '0' + (date.getDate()) : date.getDate());
  // var hh = (date.getHours() < 10 ? '0' + date.getHours() : date.getHours()) + '-';
  // var mm = (date.getMinutes() < 10 ? '0' + date.getMinutes() : date.getMinutes()) + '-';
  // var ss = (date.getSeconds() < 10 ? '0' + date.getSeconds() : date.getSeconds());
  // return YY + MM + DD +"_"+hh + mm + ss;

  return YY + MM + DD;
}

export function formatVersionHistoryDate(t) {
  if (t === null) return '';

  var date = new Date(t);
  var YY = date.getFullYear() + '/';
  var MM = (date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1) + '/';
  var DD = (date.getDate() < 10 ? '0' + (date.getDate()) : date.getDate());
  var hh = (date.getHours() < 10 ? '0' + date.getHours() : date.getHours()) + ':';
  var mm = (date.getMinutes() < 10 ? '0' + date.getMinutes() : date.getMinutes()) + ':';
  var ss = (date.getSeconds() < 10 ? '0' + date.getSeconds() : date.getSeconds());
  return YY + MM + DD +" "+hh + mm + ss;
}

export function getTextLength(str) {
  ///<summary>获得字符串实际长度，中文2，英文1</summary>
  ///<param name="str">要获得长度的字符串</param>
  var realLength = 0, len = str.length, charCode = -1;
  for (var i = 0; i < len; i++) {
    charCode = str.charCodeAt(i);
    if (charCode >= 0 && charCode <= 128) 
      realLength += 1;
    else
      realLength += 2;
  }
  return realLength;
};

export function getTextWidth(text, font='14px tabular-nums') {
  // re-use canvas object for better performance
  const canvas = getTextWidth.canvas || (getTextWidth.canvas = document.createElement("canvas"));
  const context = canvas.getContext("2d");
  context.font = font;
  const metrics = context.measureText(text);
  return metrics.width;
}

export function getDataModelerRole(user) {
  if ((user?.roles||[]).indexOf('ROLE_dataModeler_admin') !== -1) {
    return DataModelerRoleAdmin;
  } else if ((user?.roles||[]).indexOf('ROLE_dataModeler_approval') !== -1) {
    return DataModelerRoleApproval;
  }  else if ((user?.roles||[]).indexOf('ROLE_dataModeler_user') !== -1) {
    return DataModelerRoleUser;
  } else if ((user?.roles||[]).indexOf('ROLE_dataModeler_reader') !== -1) {
    return DataModelerRoleReader;
  }
  
  return '';
}

export function getScrollbarWidth() {

  // Creating invisible container
  const outer = document.createElement('div');
  outer.style.visibility = 'hidden';
  outer.style.overflow = 'scroll'; // forcing scrollbar to appear
  outer.style.msOverflowStyle = 'scrollbar'; // needed for WinJS apps
  document.body.appendChild(outer);

  // Creating inner element and placing it in the container
  const inner = document.createElement('div');
  outer.appendChild(inner);

  // Calculating difference between container's full width and the child width
  const scrollbarWidth = (outer.offsetWidth - inner.offsetWidth);

  // Removing temporary elements from the DOM
  outer.parentNode?.removeChild(outer);

  return scrollbarWidth;

}

function getOffsetTop(element, container) {
  if (!element.getClientRects().length) {
    return 0;
  }

  const rect = element.getBoundingClientRect();

  if (rect.width || rect.height) {
    if (container === window) {
      container = element.ownerDocument?.documentElement;
      return rect.top - container?.clientTop;
    }
    return rect.top - container?.getBoundingClientRect().top;
  }

  return rect.top;
}

export function getInternalCurrentAnchor(_linkIds, _offsetTop = 0, _bounds = 5, container) {
  const linkSections: Section[] = [];
  _linkIds.forEach((id) => {
    const target = container?.querySelector(`.${id}`);
    if (target) {
      const top = getOffsetTop(target, container);
      if (top < _offsetTop + _bounds) {
        linkSections.push({ id, top });
      }
    }
  });

  if (linkSections.length) {
    const maxSection = linkSections.reduce((prev, curr) => (curr.top > prev.top ? curr : prev));
    return maxSection.id;
  }
  return '';
};

export const showInfoNotifaction = function(title, tip, duration=0) {

  notification.config({ prefixCls: "yy-notification" });
  notification.info({
    message: title||'提示',
    description: (typeof tip === 'string' ? (<span dangerouslySetInnerHTML={{ __html: tip||''}} />) : tip),
    duration: duration,
  });
} 

export function checkMenuAdmit(menuinfo) {
  const menu = LocalStorage.get('menu');
  const menuadmit = LocalStorage.get('menuadmit');

  if (!menu || !menuadmit) {
    return false;
  }

  let queryurl = `/view/${menuinfo}`

  let menumessage = menu.mapurl[queryurl]
  if (menumessage) {
    let type = menumessage.id.split("-")
    let key = ""
    if (type[0] !== "item") {
      key = "sub-" + type[0]
    } 
    if (key) {
      try {
        let parent = menu.parentIdMap[key]||''
        let totalbit = menuadmit[parent.name];

        if(!parent.hidden){
          if((menumessage.bit&totalbit)===menumessage.bit){
              return true
          }else{
            showInfoNotifaction('提示', `暂无访问路由【${menumessage.name}】的权限`);
            return false
          }
        }else{
          showInfoNotifaction('提示', `暂无访问路由【${menumessage.name}】的权限`);
          return false;
        }
      } catch (error) {
        showInfoNotifaction('提示', `暂无访问路由$【${menumessage.name}】的权限`);
        return false;
      }
    } else {
      showInfoNotifaction('提示', `暂无访问路由【${menumessage.name}】的权限`);
      return false
    }
  }

  return false;
}