import React, { useState, useContext, useMemo } from 'react';
import styled from '@emotion/styled';
import PropTypes from 'prop-types';
import Dialog from '@mui/material/Dialog';
import Box from '@mui/material/Box';
import DialogContent from '@mui/material/DialogContent';
import DialogTitle from '@mui/material/DialogTitle';
import DialogActions from '@mui/material/DialogActions';
import UpdateIcon from '@mui/icons-material/Update';
import { Icon } from '@iconify/react';
import Grid from '@mui/material/Grid';
import ArrowForwardIcon from '@mui/icons-material/ArrowForward';
import Checkbox from '@mui/material/Checkbox';
import FormControlLabel from '@mui/material/FormControlLabel';
import Switch from '@mui/material/Switch';
import { APP_STRUCT_VERSION } from '@abtnode/constant';
import Spinner from '@mui/material/CircularProgress';
import { LocaleContext } from '@arcblock/ux/lib/Locale/context';
import Button from '@arcblock/ux/lib/Button';
import Empty from '@arcblock/ux/lib/Empty';
import { forEachChildSync, isInProgress } from '@blocklet/meta/lib/util';
import { formatError } from '@blocklet/error';
import Toast from '@arcblock/ux/lib/Toast';
import TuneOutlinedIcon from '@mui/icons-material/TuneOutlined';
import { useDeletingBlockletContext } from '../../contexts/deleting-blocklets';
import AutoCheckUpdate from '../auto-check-update';
import { useNodeContext } from '../../contexts/node';
import { sleep, BlockletAdminRoles } from '../../util';
import Permission from '../../permission';
import ComponentConfiguration from './configuration';
import AddComponentButton from './add-component/add-component-button';
import AddRule from '../router/action/add-rule';
import RuleList from '../router/rule-list';
import useCheckUpdateByUrl from '../../hooks/use-check-update-by-url';
import useGetInstallComponentByUrl from '../../hooks/use-install-component-by-url';
import ComponentCell, { StyledBadge, StyledComponentRow } from './component-cell';
import OptionalComponentCell from './optional-component-cell';
import AddComponentDialog from './add-component/add-component-dialog';
import Actions from '../../actions';
import BlockletPreferences from './blocklet-preference';
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
export default function BlockletComponent({
  blocklet,
  onUpdate = () => {},
  getComponentUrl = () => window.location.origin,
  ...rest
}) {
  const {
    t
  } = useContext(LocaleContext);
  const {
    api,
    inService,
    info
  } = useNodeContext();
  const {
    addDeletingDid,
    removeDeletingDid,
    matchDeletingDid
  } = useDeletingBlockletContext();
  const [loading, setLoading] = useState(false);
  const [updateConfirm, setUpdateConfirm] = useState(null);
  const [showSettings, setShowSettings] = useState(null);
  const [showContainer, setShowContainer] = useState(false);
  const [showAddRule, setShowAddRule] = useState(false);
  const [showEnvironment, setShowEnvironment] = useState(false);
  const [showPreferences, setShowPreferences] = useState(false);
  const [installComponentMeta, setInstallComponentMeta] = useState(null);
  const needMigration = blocklet && blocklet.structVersion !== APP_STRUCT_VERSION;

  // update dot is not used but maybe useful in the further
  const [showUpdateDot, setShowUpdateDot] = useState(false);
  const components = [...blocklet.children] || [];
  if (blocklet.meta.group !== 'gateway') {
    // add root blocklet to table list
    components.unshift(blocklet);
  }
  matchDeletingDid(components.map(e => e.meta.did));
  const checkForUpdates = async () => {
    if (loading) {
      return;
    }
    setLoading(true);
    try {
      // check child component version
      const {
        updateId,
        updateList
      } = (await api.checkComponentsForUpdates({
        input: {
          did: blocklet.meta.did
        }
      })).preUpdateInfo || {};
      setLoading(false);
      if (!updateId) {
        Toast.info(t('blocklet.component.noUpdate'));
        return;
      }
      const list = [];
      forEachChildSync(blocklet, (b, {
        id,
        ancestors
      }) => {
        const updateItem = updateList.find(x => x.id === id);
        if (updateItem) {
          const name = ancestors.slice(1).concat(b).map(x => x.meta.title || x.meta.name).join(' / ');

          // groupId 为一级组件的 id
          const groupId = (ancestors[1] || b).meta.did;
          list.push({
            groupId,
            name,
            version: b.meta.version,
            newVersion: updateItem.meta.version
          });
        }
      });
      const checks = {};
      list.forEach(x => {
        if (!checks[x.groupId]) {
          checks[x.groupId] = true;
        } else {
          x.disabled = true;
        }
      });
      setUpdateConfirm({
        params: {
          updateId
        },
        list,
        checks,
        hasChecks: true
      });
    } catch (err) {
      setLoading(false);
      Toast.error(formatError(err));
    }
  };
  const onConfirmUpdate = async () => {
    if (loading) {
      return;
    }
    try {
      setLoading(true);
      const selectedComponents = Object.keys(updateConfirm.checks).filter(x => updateConfirm.checks[x]);
      const input = {
        updateId: updateConfirm.params.updateId,
        rootDid: blocklet.meta.did,
        selectedComponents
      };
      await api.upgradeComponents({
        input
      });
      setLoading(false);
      setUpdateConfirm(null);
      setShowUpdateDot(null);
    } catch (error) {
      setLoading(false);
      Toast.error(formatError(error));
    }
  };
  const removeComponent = async (d, type) => {
    addDeletingDid(d.meta.did);
    try {
      await api.deleteComponent({
        input: {
          did: d.meta.did,
          keepData: type === 'keepData',
          rootDid: blocklet.meta.did
        }
      });
      await sleep(800);
    } catch (err) {
      Toast.error(formatError(err));
      removeDeletingDid(d.meta.did);
    }
  };
  const startComponent = async d => {
    try {
      await api.startBlocklet({
        input: {
          did: blocklet.meta.did,
          componentDids: [d.meta.did]
        }
      });
      await sleep(800);
    } catch (err) {
      Toast.error(formatError(err));
    }
  };
  const stopComponent = async d => {
    try {
      await api.stopBlocklet({
        input: {
          did: blocklet.meta.did,
          componentDids: [d.meta.did]
        }
      });
      await sleep(800);
    } catch (err) {
      Toast.error(formatError(err));
    }
  };
  const restartComponent = async d => {
    try {
      await api.restartBlocklet({
        input: {
          did: blocklet.meta.did,
          componentDids: [d.meta.did]
        }
      });
      await sleep(800);
    } catch (err) {
      Toast.error(formatError(err));
    }
  };
  const onUpdateChecksChange = (e, groupId) => {
    const {
      checked: newValue
    } = e.target;
    setUpdateConfirm(x => {
      const checks = Object.entries(x.checks).reduce((o, [key, oldValue]) => {
        o[key] = groupId === key || groupId === 'all' ? newValue : oldValue;
        return o;
      }, {});
      const hasChecks = Object.values(checks).includes(true);
      return {
        ...x,
        checks,
        hasChecks
      };
    });
  };

  // 是否全选
  const checkedAll = useMemo(() => {
    return updateConfirm?.list.filter(x => !x.disabled).every(x => updateConfirm.checks[x.groupId]);
  }, [updateConfirm]);
  useCheckUpdateByUrl(checkForUpdates);
  const _installComponentMeta = useGetInstallComponentByUrl({
    blocklet,
    scrollToComponent: true
  });
  const parseInstallComponentMeta = installComponentMeta || _installComponentMeta;
  return /*#__PURE__*/_jsxs(Div, {
    component: "div",
    ...rest,
    onUpdate: onUpdate,
    children: [/*#__PURE__*/_jsxs(TitleRow, {
      display: "flex",
      children: [/*#__PURE__*/_jsxs(TitleItem, {
        flexDirection: "row",
        className: "title",
        display: "flex",
        alignItems: "center",
        children: [components?.length ? `${t('common.components')} (${components.length})` : `${t('common.components')}`, !needMigration && /*#__PURE__*/_jsx(Permission, {
          permission: inService ? '' : 'mutate_blocklets',
          role: inService ? BlockletAdminRoles : [],
          children: /*#__PURE__*/_jsx(AutoCheckUpdate, {
            children: /*#__PURE__*/_jsx(StyledBadge, {
              top: 1.2,
              right: 0.4,
              color: "error",
              badgeContent: "",
              variant: "dot",
              invisible: !showUpdateDot,
              children: /*#__PURE__*/_jsxs(Button, {
                disabled: loading || isInProgress(blocklet.status),
                onClick: () => {
                  checkForUpdates();
                },
                "data-cy": "check-for-updates",
                children: [/*#__PURE__*/_jsx(Box, {
                  sx: {
                    ml: 0.5,
                    mr: 0.5,
                    display: 'flex'
                  },
                  children: loading ? /*#__PURE__*/_jsx(Spinner, {
                    size: 16
                  }) : /*#__PURE__*/_jsx(UpdateIcon, {
                    style: {
                      fontSize: '1em'
                    }
                  })
                }), t('blocklet.component.checkUpdateTitle')]
              })
            })
          })
        })]
      }), /*#__PURE__*/_jsx(Permission, {
        permission: inService ? '' : 'mutate_blocklets',
        role: inService ? BlockletAdminRoles : [],
        children: /*#__PURE__*/_jsxs(Box, {
          sx: {
            display: 'flex',
            alignItems: 'center',
            gap: 0.5
          },
          children: [!needMigration && /*#__PURE__*/_jsx(AddComponentButton, {
            blocklet: blocklet,
            serverVersion: info.version,
            disabled: loading || isInProgress(blocklet.status)
          }), /*#__PURE__*/_jsx(Actions, {
            "data-cy": "component-actions",
            actions: [{
              icon: /*#__PURE__*/_jsx(Icon, {
                icon: "fluent:link-20-filled"
              }),
              onClick: () => setShowAddRule(true),
              text: t('router.rule.add.title'),
              disabled: loading || isInProgress(blocklet.status)
            }, ...(!needMigration ? [{
              icon: /*#__PURE__*/_jsx(Icon, {
                icon: "mdi:variable"
              }),
              onClick: () => {
                setShowEnvironment(true);
              },
              text: t('common.environments')
            }, {
              icon: /*#__PURE__*/_jsx(TuneOutlinedIcon, {}),
              onClick: () => {
                setShowPreferences(true);
              },
              text: t('common.preferences')
            }] : [])].filter(Boolean)
          })]
        })
      })]
    }), components?.length ? /*#__PURE__*/_jsxs(_Fragment, {
      children: [/*#__PURE__*/_jsxs(Box, {
        sx: {
          mt: 2
        },
        children: [blocklet.meta.group !== 'gateway' && /*#__PURE__*/_jsx(ComponentCell, {
          blocklet: blocklet,
          app: blocklet,
          onRemove: removeComponent,
          onStart: startComponent,
          onStop: stopComponent,
          onRestart: restartComponent,
          getComponentUrl: getComponentUrl
        }, `0-${blocklet.meta.did}`), blocklet.children.map(component => {
          return /*#__PURE__*/_jsx(ComponentCell, {
            depth: 1,
            blocklet: component,
            ancestors: [blocklet],
            app: blocklet,
            onRemove: removeComponent,
            onStart: startComponent,
            onStop: stopComponent,
            onRestart: restartComponent,
            getComponentUrl: getComponentUrl
          }, `1-${component.meta.did}`);
        })]
      }, `top-blocklet-${blocklet.meta.did}`), blocklet.optionalComponents?.map(component => /*#__PURE__*/_jsx(StyledComponentRow, {
        children: /*#__PURE__*/_jsx(OptionalComponentCell, {
          setInstallComponentMeta: setInstallComponentMeta,
          ...component
        })
      }, component.meta.did))]
    }) : /*#__PURE__*/_jsx(Box, {
      sx: {
        mt: 8
      },
      children: /*#__PURE__*/_jsx(Empty, {
        children: t('blocklet.component.noComponent')
      })
    }), !!blocklet.site.rules.length && /*#__PURE__*/_jsx(Box, {
      sx: {
        mt: 0,
        '.component-item__indent': {
          pl: 2,
          width: 0
        }
      },
      children: /*#__PURE__*/_jsx(RuleList, {})
    }), !!updateConfirm && /*#__PURE__*/_jsx(Dialog, {
      open: true,
      fullWidth: true,
      children: /*#__PURE__*/_jsxs(Box, {
        sx: {
          paddingY: 1.5
        },
        children: [/*#__PURE__*/_jsx(DialogTitle, {
          children: t('blocklet.component.updateTitle')
        }), /*#__PURE__*/_jsxs(Box, {
          component: DialogContent,
          sx: {
            py: 4
          },
          children: [updateConfirm.list.filter(x => !x.disabled).length > 1 && /*#__PURE__*/_jsxs(Box, {
            sx: {
              display: 'flex',
              alignItems: 'center'
            },
            children: [/*#__PURE__*/_jsx(Checkbox, {
              checked: checkedAll,
              onChange: e => onUpdateChecksChange(e, 'all')
            }), /*#__PURE__*/_jsx(Box, {
              children: checkedAll ? t('common.unselectAll') : t('common.selectAll')
            })]
          }), updateConfirm.list.map(x => /*#__PURE__*/_jsxs(Box, {
            sx: {
              display: 'flex',
              alignItems: 'center',
              mb: 1
            },
            children: [/*#__PURE__*/_jsx(Checkbox, {
              checked: updateConfirm.checks[x.groupId],
              onChange: e => onUpdateChecksChange(e, x.groupId),
              style: {
                marginLeft: x.disabled ? 16 : 0,
                alignSelf: 'flex-start'
              },
              defaultChecked: true,
              disabled: x.disabled
            }), /*#__PURE__*/_jsxs(Box, {
              sx: {
                flexGrow: 1
              },
              children: [/*#__PURE__*/_jsx(Box, {
                xs: 8,
                sx: {
                  pt: 1
                },
                children: x.name
              }), x.version && /*#__PURE__*/_jsxs(Grid, {
                container: true,
                spacing: 2,
                sx: {
                  fontSize: 'h6.fontSize',
                  alignItems: 'center'
                },
                children: [/*#__PURE__*/_jsx(Grid, {
                  size: 3,
                  children: x.version
                }), /*#__PURE__*/_jsx(Grid, {
                  size: 1,
                  children: /*#__PURE__*/_jsx(ArrowForwardIcon, {
                    style: {
                      fontSize: '0.9em'
                    }
                  })
                }), /*#__PURE__*/_jsx(Grid, {
                  size: 3,
                  children: /*#__PURE__*/_jsx(Box, {
                    sx: {
                      color: 'secondary.main'
                    },
                    children: x.newVersion
                  })
                })]
              })]
            }, `${x.name}-${x.newVersion}`)]
          }, x.name))]
        }), /*#__PURE__*/_jsxs(DialogActions, {
          style: {
            padding: '8px 24px 24px'
          },
          children: [/*#__PURE__*/_jsx(Button, {
            onClick: () => {
              setUpdateConfirm(null);
            },
            children: t('common.cancel')
          }), /*#__PURE__*/_jsxs(Button, {
            onClick: e => {
              e.stopPropagation();
              onConfirmUpdate();
            },
            color: "primary",
            disabled: loading || !updateConfirm.hasChecks,
            variant: "contained",
            autoFocus: true,
            children: [loading && /*#__PURE__*/_jsx(Spinner, {
              size: 16
            }), t('common.update')]
          })]
        })]
      })
    }), !!showSettings && /*#__PURE__*/_jsx(Dialog, {
      open: true,
      fullWidth: true,
      onClose: () => setShowSettings(false),
      children: /*#__PURE__*/_jsxs(Box, {
        sx: {
          paddingY: 1.5
        },
        children: [/*#__PURE__*/_jsx(DialogTitle, {
          children: t('common.configuration')
        }), /*#__PURE__*/_jsx(DialogContent, {
          children: /*#__PURE__*/_jsx(Box, {
            sx: {
              py: 2
            },
            children: /*#__PURE__*/_jsx(FormControlLabel, {
              control: /*#__PURE__*/_jsx(Switch, {
                checked: showContainer,
                onChange: e => setShowContainer(!!e.target.checked)
              }),
              label: t('blocklet.component.showContainer')
            })
          })
        })]
      })
    }), /*#__PURE__*/_jsx(AddComponentDialog, {
      selectedMeta: parseInstallComponentMeta,
      blocklet: blocklet,
      showDialog: !!parseInstallComponentMeta,
      setShowDialog: () => setInstallComponentMeta(null)
    }), showAddRule && /*#__PURE__*/_jsx(AddRule, {
      hiddenChildren: true,
      open: true,
      onClose: () => setShowAddRule(false)
    }), showEnvironment && /*#__PURE__*/_jsx(ComponentConfiguration, {
      open: true,
      onClose: () => setShowEnvironment(false),
      hiddenChildren: true,
      blocklet: blocklet,
      ancestors: []
    }), showPreferences && /*#__PURE__*/_jsx(BlockletPreferences, {
      open: true,
      onClose: () => setShowPreferences(false),
      blocklet: blocklet,
      ancestors: []
    })]
  });
}
BlockletComponent.propTypes = {
  blocklet: PropTypes.object.isRequired,
  onUpdate: PropTypes.func,
  getComponentUrl: PropTypes.func
};
const Div = styled.div`
  .title {
    font-size: 1.2rem;
    font-weight: bold;
  }

  @keyframes showDelay {
    0% {
      opacity: 0;
    }

    100% {
      opacity: 1;
    }
  }

  .component-item {
    animation: showDelay 0.75s ease 1;
  }
`;
const TitleRow = styled(Box)`
  ${props => props.theme.breakpoints.up('sm')} {
    flex-direction: row;
    justify-content: space-between;
    align-items: center;
  }
  ${props => props.theme.breakpoints.down('sm')} {
    flex-direction: column;
    justify-content: flex-end;
    align-items: flex-end;
    .sm-hide-icon > svg {
      display: none;
    }
  }
`;
const TitleItem = styled(Box)`
  ${props => props.theme.breakpoints.down('sm')} {
    width: 100%;
    justify-content: space-between;
  }
`;