import { Icon } from '@iconify/react';
import { Box, Backdrop, useMediaQuery, SwipeableDrawer, Typography, Tooltip } from '@mui/material';
import type { BackdropProps } from '@mui/material';

import styled from '@emotion/styled';
import Button from '@arcblock/ux/lib/Button';
import PhoneInput, {
  PhoneValue,
  validatePhoneNumber,
  getDialCodeByCountry,
  getCountryNameByCountry,
  detectCountryFromPhone,
} from '@arcblock/ux/lib/PhoneInput';
import cloneDeep from 'lodash/cloneDeep';
import omit from 'lodash/omit';
import { mergeSx } from '@arcblock/ux/lib/Util/style';
import { LOGIN_PROVIDER } from '@arcblock/ux/lib/Util/constant';
import { useCreation, useMemoizedFn, useReactive } from 'ahooks';
import { useMemo, useRef, useState, memo, useEffect } from 'react';
import { translate } from '@arcblock/ux/lib/Locale/util';
import isEmail from 'validator/lib/isEmail';
import isPostalCode from 'validator/lib/isPostalCode';
import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
import { useBrowser } from '@arcblock/react-hooks';
import Clock from '@arcblock/ux/lib/UserCard/Content/clock';

import EmailIcon from '@arcblock/icons/lib/Email';
import PhoneIcon from '@arcblock/icons/lib/Phone';
import TimezoneIcon from '@arcblock/icons/lib/Timezone';
import LocationIcon from '@arcblock/icons/lib/Location';

import { translations } from '../../libs/locales';
import type { User, UserAddress, UserMetadata, UserPhoneProps } from '../../../@types';
import EditableField, { commonInputStyle, inputFieldStyle } from '../editable-field';
import { LinkPreviewInput } from './link-preview-input';
import { defaultButtonStyle, primaryButtonStyle } from './utils';
import { TimezoneSelect } from './timezone-select';
import AddressEditor from './address';

const iconSize = {
  width: 20,
  height: 20,
};

const bioMaxLength = 200;

const BackdropWrap = memo(function BackdropWrap({
  ref,
  ...backdropProps
}: BackdropProps & {
  // eslint-disable-next-line react/require-default-props
  ref?: React.Ref<unknown>;
}) {
  return (
    <Backdrop
      ref={ref}
      component="div"
      style={{
        backgroundColor: 'rgba(0, 0, 0, 0.6)',
        backdropFilter: 'blur(3px)',
        touchAction: 'none',
      }}
      {...backdropProps}
      key="background"
    />
  );
});

// 添加 displayName
BackdropWrap.displayName = 'BackdropWrap';

export default function UserMetadataComponent({
  isMyself,
  user,
  onSave,
  isMobile,
}: {
  isMobile: boolean;
  isMyself: boolean;
  user: User;
  onSave: (v: { metadata: UserMetadata; address: UserAddress }) => void;
}) {
  const [editable, setEditable] = useState(false);
  const [visible, setVisible] = useState(false);
  const drawerDragger = useRef(null);
  const browser = useBrowser();
  const isMobileView = useMediaQuery('(max-width:640px)') || browser.mobile.any;
  const validateMsg = useReactive<Record<string, string>>({
    email: '',
    phone: '',
  });
  const addressValidateMsg = useReactive<Record<string, string>>({
    country: '',
    province: '',
    city: '',
    line1: '',
    line2: '',
    postalCode: '',
  });

  useEffect(() => {
    if (!isMobileView) {
      setVisible(false);
    }
  }, [isMobileView]);

  const phoneVerified = useCreation(() => {
    return user?.phoneVerified ?? false;
  }, [user?.phoneVerified]);

  const emailVerified = useCreation(() => {
    return user?.emailVerified ?? false;
  }, [user?.emailVerified]);

  const { locale } = useLocaleContext();
  const t = useMemoizedFn((key, data = {}) => {
    return translate(translations, key, locale, 'en', data);
  });

  const metadata: UserMetadata = useReactive(
    user?.metadata
      ? cloneDeep(user.metadata)
      : {
          joinedAt: user?.createdAt,
          email: user?.email,
          phone: {
            country: 'cn',
            phoneNumber: user?.phone ?? '',
          },
        }
  );

  const address: UserAddress = useReactive(
    user?.address
      ? cloneDeep(user.address)
      : {
          country: '',
          province: '',
          city: '',
          line1: '',
          line2: '',
          postalCode: '',
        }
  );

  // 判断是否支持地址, 如果已经支持则返回 {}, 否则返回为 undefined
  const isSupportAddress = useCreation(() => {
    return !!user?.address;
  }, [user?.address?.country]);

  /**
   * 获取默认的国家
   * 如果 address 中存储有 country 信息就使用 address 中的信息
   * 如果没有根据 locale 获取，如果是中文环境，默认 country 是中国，如果是其他就选择美国
   */
  const defaultCountry = useMemo(() => {
    if (user?.address?.country) {
      return user.address.country;
    }

    return locale === 'zh' ? 'cn' : 'us';
  }, [user?.address?.country, locale]);

  const phoneValue = useCreation((): PhoneValue => {
    const phone = metadata.phone ??
      user?.phone ?? {
        country: defaultCountry,
        phone: '',
      };

    if (phone && typeof phone === 'string') {
      const detectedCountry = detectCountryFromPhone(phone);
      return {
        country: detectedCountry || defaultCountry,
        phone,
      };
    }
    if (phone && typeof phone === 'object') {
      const { country: phoneCountry = '', phoneNumber = '' } = phone as UserPhoneProps;
      const detectedCountry = !phoneCountry ? detectCountryFromPhone(phoneNumber) || '' : phoneCountry;

      return {
        country: detectedCountry,
        phone: phoneNumber || '',
      };
    }

    return {
      country: defaultCountry,
      phone: '',
    };
  }, [metadata.phone, user?.phone, defaultCountry]);

  const onChange = (v: any, field: keyof UserMetadata | 'email' | 'phone') => {
    metadata[field] = v;
  };

  const onAddressChange = (field: keyof UserAddress, value: string) => {
    address[field] = value;

    if (field === 'city') {
      onChange(value, 'location');
    }

    if (field === 'postalCode') {
      addressValidateMsg.postalCode =
        value && !isPostalCode(value, 'any') ? t('profile.address.invalidPostalCode') : '';
    } else {
      addressValidateMsg[field] = '';
    }
  };

  const onEdit = () => {
    if (!isMobileView) {
      setEditable(true);
    } else {
      setVisible(true);
    }
  };

  const onCancel = () => {
    const defaultMetadata: UserMetadata = cloneDeep(user?.metadata) ?? {};
    if (defaultMetadata) {
      Object.keys(metadata).forEach((key) => {
        const k = key as keyof UserMetadata;
        (metadata[k] as any) = defaultMetadata[k];
      });
    }

    const defaultAddress: UserAddress = cloneDeep(user?.address) ?? {};
    if (defaultAddress) {
      Object.keys(address).forEach((key) => {
        const k = key as keyof UserAddress;
        (address[k] as any) = defaultAddress[k];
      });
    }

    // 清空校验状态
    [validateMsg, addressValidateMsg].forEach((o) => {
      Object.keys(o).forEach((key) => {
        o[key] = '';
      });
    });

    if (!isMobileView) {
      setEditable(false);
    } else {
      setVisible(false);
    }
  };

  const links = useMemo(() => {
    const defaultLinks = metadata?.links?.map((link) => link.url) || [''];
    return defaultLinks.length > 0 ? defaultLinks : [''];
  }, [metadata.links]);

  const handleLinksChange = (values: string[]) => {
    const newLinks = values.map((link) => {
      if (!link) {
        return {
          url: link,
        };
      }
      const targetLink = metadata.links?.find((l) => l.url === link);
      if (targetLink) {
        return {
          ...targetLink,
          url: link,
        };
      }
      return {
        url: link,
        favicon: link,
      };
    });
    onChange(newLinks, 'links');
  };

  const handleSave = () => {
    Object.keys(metadata).forEach((key) => {
      const k = key as keyof UserMetadata;
      const value = metadata[k];
      if (value && typeof value === 'string') {
        (metadata[k] as string) = value.trim();
      }
      if (k === 'bio') {
        metadata[k] = metadata[k]?.slice(0, bioMaxLength);
      }
      if (k === 'timezone') {
        metadata[k] = (value as string) || '';
      }
      if (k === 'phone' && value && typeof value === 'object') {
        const phoneInput = value as UserPhoneProps;
        const dialCode = getDialCodeByCountry(phoneInput.country);
        // 去除电话号码中的区号部分
        const phoneWithoutCode = phoneInput.phoneNumber?.replace(new RegExp(`^\\+${dialCode}`), '') || '';

        const hasActualPhoneNumber = phoneWithoutCode?.trim().length > 0;

        metadata[k] = {
          country: phoneInput.country,
          ...(hasActualPhoneNumber ? { phoneNumber: phoneInput.phoneNumber } : {}),
        };
      }
    });

    // 单独处理邮政编码验证，避免嵌套三元表达式
    if (address.postalCode && !isPostalCode(address.postalCode, 'any')) {
      addressValidateMsg.postalCode = t('profile.address.invalidPostalCode');
    }

    // 检查是否有错误
    if ([validateMsg, addressValidateMsg].some((o) => Object.values(o).some((e) => e))) {
      return;
    }

    // 兼容代码。移除之前的 detailedAddress 字段
    const newAddress = omit(address, 'detailedAddress');
    // 添加默认值
    if (!newAddress.country) {
      newAddress.country = defaultCountry;
    }

    onSave({ metadata, address: newAddress });
    setEditable(false);
    setVisible(false);
  };

  const renderEdit = (editing: boolean, mode: 'drawer' | 'self' = 'self') => {
    return (
      <MetadataInfo
        pt={2}
        display="flex"
        flexDirection="column"
        justifyContent="space-between"
        alignItems="flex-start"
        gap={!isMobile ? '16px' : '4px'}>
        <EditableField
          value={metadata.bio ?? ''}
          onChange={(value) => onChange(value, 'bio')}
          editable={editing}
          placeholder="Bio"
          component="textarea"
          inline={false}
          rows={3}
          label={t('profile.bio')}
          maxLength={bioMaxLength}
          style={{
            ...(editing ? { marginBottom: 8 } : {}),
          }}
        />
        {!editing && isMyself ? (
          <Button
            size={isMobile ? 'small' : 'large'}
            variant="outlined"
            sx={{
              ...defaultButtonStyle,
              mb: !isMobile ? 2 : '4px',
              mt: !isMobile ? 2 : '4px',
              height: !isMobile ? '40px' : '32px',
            }}
            onClick={onEdit}
            fullWidth>
            {t('profile.editProfile')}
          </Button>
        ) : null}
        {editing && isMyself && isSupportAddress ? (
          <AddressEditor
            address={address}
            errors={addressValidateMsg}
            handleChange={onAddressChange}
            defaultCountry={defaultCountry}
          />
        ) : (
          <EditableField
            value={metadata.location ?? user?.address?.city ?? ''}
            onChange={(value) => onChange(value, 'location')}
            editable={editing}
            placeholder="Location"
            label={t('profile.location')}
            tooltip={
              isMyself && (address.line1 || address.line2) ? (
                <>
                  {['line1', 'line2'].map((k) => {
                    const value = address[k as keyof UserAddress];
                    if (!value) {
                      return null;
                    }
                    return (
                      <Box key={k}>
                        <Typography
                          variant="caption"
                          component="p"
                          sx={{
                            fontWeight: 600,
                            mb: 0,
                          }}>
                          {t(`profile.address.${k}`)}
                        </Typography>
                        <Typography variant="caption" component="span">
                          {address[k as keyof UserAddress]}
                        </Typography>
                      </Box>
                    );
                  })}
                </>
              ) : null
            }
            renderValue={() => {
              const countryName = address?.country ? getCountryNameByCountry(address?.country) : '';
              const fullLocation = [countryName, address.province, address.city || metadata.location || '']
                .filter(Boolean)
                .join(' ');
              return <Typography component="span">{fullLocation}</Typography>;
            }}
            icon={<LocationIcon {...iconSize} />}
          />
        )}
        <EditableField
          value={metadata.timezone || ''}
          onChange={(value) => onChange(value, 'timezone')}
          editable={editing}
          placeholder="timezone"
          icon={<TimezoneIcon {...iconSize} />}
          label={t('profile.timezone')}
          renderValue={(value) => {
            return <Clock value={value} />;
          }}>
          <TimezoneSelect
            value={metadata.timezone ?? ''}
            onChange={(value) => onChange(value, 'timezone')}
            disabled={!editing}
            mode={mode}
          />
        </EditableField>
        <EditableField
          value={metadata.email ?? user?.email ?? ''}
          editable={editing}
          hidePreview={!isMyself}
          disabled={user?.sourceProvider === LOGIN_PROVIDER.EMAIL}
          canEdit={!emailVerified}
          verified={emailVerified}
          placeholder="Email"
          icon={<EmailIcon {...iconSize} />}
          label={
            <>
              {t('profile.email')}
              {user?.sourceProvider === LOGIN_PROVIDER.EMAIL ? (
                <Tooltip title={t('profile.emailSourceProviderNotAllowEdit')}>
                  <Box
                    component={Icon}
                    icon="mdi:info-outline"
                    sx={{
                      verticalAlign: 'middle',
                      ml: 0.25,
                    }}
                  />
                </Tooltip>
              ) : null}
            </>
          }
          onChange={(value) => onChange(value, 'email')}
          errorMsg={validateMsg.email}
          renderValue={(value) =>
            isMyself ? (
              <a
                href={`mailto:${value}`}
                style={{
                  color: 'inherit',
                  textDecoration: 'none',
                }}>
                {value}
              </a>
            ) : null
          }
          onValueValidate={(value) => {
            let msg = '';
            if (!!value && !isEmail(value)) {
              msg = t('profile.emailInvalid');
            }
            validateMsg.email = msg;
          }}
        />
        <EditableField
          value={phoneValue.phone}
          editable={editing}
          hidePreview={!isMyself}
          canEdit={!phoneVerified}
          verified={phoneVerified}
          placeholder="Phone"
          icon={<PhoneIcon {...iconSize} />}
          onChange={(value) => onChange(value, 'phone')}
          label={t('profile.phone')}
          renderValue={() => {
            return isMyself ? <PhoneInput value={phoneValue} preview /> : null;
          }}>
          <PhoneInput
            variant="outlined"
            className="editable-field"
            InputProps={{
              sx: { backgroundColor: 'transparent' },
              placeholder: 'Phone',
            }}
            value={phoneValue}
            error={!!validateMsg.phone}
            helperText={validateMsg.phone}
            sx={mergeSx(inputFieldStyle, !validateMsg.phone ? commonInputStyle : {})}
            onChange={(value: any) => {
              const isValid = validatePhoneNumber(value.phone, value.country);
              if (!isValid) {
                validateMsg.phone = t('profile.phoneInvalid');
              } else {
                validateMsg.phone = '';
              }
              onChange(
                {
                  country: value.country,
                  phoneNumber: value.phone,
                },
                'phone'
              );
            }}
          />
        </EditableField>
        <LinkPreviewInput editable={editing} links={links} onChange={handleLinksChange} />
        {editing && isMyself ? (
          <Box
            style={{ width: '100%' }}
            sx={{
              display: 'flex',
              gap: 1,
              justifyContent: 'flex-end',
              flexDirection: mode === 'drawer' ? 'column' : 'row',
            }}>
            <Button
              fullWidth={mode === 'drawer'}
              size="small"
              variant="outlined"
              sx={{ ...defaultButtonStyle, minWidth: '54px' }}
              onClick={onCancel}>
              {t('common.cancel')}
            </Button>
            <Button
              fullWidth={mode === 'drawer'}
              size="small"
              disabled={!!validateMsg.email || !!validateMsg.phone}
              variant="outlined"
              sx={{
                ...primaryButtonStyle,
                minWidth: '54px',
                '&.Mui-disabled': {
                  backgroundColor: 'rgba(0, 0, 0, 0.12)',
                },
              }}
              onClick={handleSave}>
              {t('common.save')}
            </Button>
          </Box>
        ) : null}
      </MetadataInfo>
    );
  };

  return (
    <>
      {renderEdit(editable)}
      {isMobileView && (
        <SwipeableDrawer
          sx={{
            zIndex: 9999,
          }}
          disableSwipeToOpen
          onOpen={onEdit}
          open={visible}
          anchor="bottom"
          onClose={onCancel}
          slots={{
            backdrop: BackdropWrap,
          }}
          slotProps={{
            paper: {
              sx: {
                boxShadow: '0px -2px 16px 0px rgba(0, 0, 0, 0.08)',
                borderRadius: 1.5, // 保持跟 DID Wallet 一致
                borderBottomLeftRadius: 0,
                borderBottomRightRadius: 0,
              },
            },
          }}>
          <Box
            ref={drawerDragger}
            sx={{
              padding: '16px 32px',
              margin: '-8px auto -16px',
              zIndex: 1,
            }}>
            <Box
              sx={{
                width: '48px',
                height: '4px',
                borderRadius: '100vw',
                backgroundColor: 'rgba(0, 0, 0, 0.2)',
              }}
            />
          </Box>
          <Box
            sx={{
              p: 2,
              maxHeight: '500px',
              overflowY: 'auto',
            }}>
            {renderEdit(true, 'drawer')}
          </Box>
        </SwipeableDrawer>
      )}
    </>
  );
}
const MetadataInfo = styled(Box)`
  width: 100%;

  .MuiOutlinedInput-root {
    padding: 8px;
    .MuiOutlinedInput-input {
      padding: 0;
    }
  }
  .timezone-select {
    min-width: 150px;
    &.disabled {
      padding: 4px 8px;
      fieldset {
        border: unset;
      }
      svg {
        display: none;
      }
    }
  }
  .info-row {
    display: flex;
    flex-direction: row;
    align-items: center;
    justify-content: center;
    gap: 4px;
    margin: 0;
    p {
      display: flex;
      align-items: center;
      margin: 0;
      font-size: 16px;
      font-weight: 400;
      color: #666;
    }
  }
`;
