import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
import { FormInput, FormLabel } from '@blocklet/payment-react';
import { AddOutlined, Autorenew, DeleteOutlineOutlined, FormatAlignLeft } from '@mui/icons-material';
import { Box, Button, Divider, IconButton, Stack, TextField, InputAdornment, Tooltip } from '@mui/material';
import { useEffect, useRef, useState, useCallback } from 'react';
import { useFieldArray, useFormContext } from 'react-hook-form';
import { isObject, debounce } from 'lodash';

import { isObjectContent } from '../../libs/util';

export default function MetadataForm({
  title = undefined,
  actions = null,
  minHeight = 'auto',
  showModeToggle = true,
  color = 'primary',
  name = 'metadata',
}: {
  title?: string;
  actions?: React.ReactNode;
  minHeight?: string;
  showModeToggle?: boolean;
  color?: 'primary' | 'inherit';
  name?: string;
}) {
  const { t } = useLocaleContext();
  const {
    control,
    formState: { errors },
    setValue,
    getValues,
  } = useFormContext();

  const metadata = useFieldArray({ control, name });
  const lastItemRef = useRef<HTMLDivElement | null>(null);
  const errorRef = useRef<HTMLDivElement | null>(null);
  const initRef = useRef(false);

  const [mode, setMode] = useState<'form' | 'json'>('form');
  const [jsonValue, setJsonValue] = useState('');
  const [formatError, setFormatError] = useState<string | null>(null);

  // Initialize JSON value from form data
  useEffect(() => {
    const formData = getValues();
    if (Array.isArray(formData.metadata)) {
      const metadataObj = formData.metadata.reduce((acc: any, x: any) => {
        if (x.key) {
          acc[x.key] = isObjectContent(x.value) ? JSON.parse(x.value) : x.value;
        }
        return acc;
      }, {});
      setJsonValue(JSON.stringify(metadataObj, null, 2));
    }
  }, [getValues]);

  // Debounced function to sync JSON changes to form
  const debouncedSyncToForm = useCallback(
    debounce((jsonString: string) => {
      try {
        const parsedData = JSON.parse(jsonString);
        const formMetadata: Array<{ key: string; value: string }> = [];
        const orderedKeys = Object.keys(JSON.parse(JSON.stringify(parsedData)));
        orderedKeys.forEach((key) => {
          formMetadata.push({
            key,
            value: isObject(parsedData[key]) ? JSON.stringify(parsedData[key]) : parsedData[key],
          });
        });

        setValue('metadata', formMetadata.length > 0 ? formMetadata : [{ key: '', value: '' }]);
      } catch (err) {
        // eslint-disable-next-line no-console
        console.log(err);
      }
    }, 500),
    [setValue]
  );

  // Sync JSON changes to form when in JSON mode
  useEffect(() => {
    if (mode === 'json') {
      debouncedSyncToForm(jsonValue);
    }
  }, [jsonValue, mode, debouncedSyncToForm]);

  // Cleanup debounce on unmount
  useEffect(() => {
    return () => {
      debouncedSyncToForm.cancel();
    };
  }, [debouncedSyncToForm]);

  useEffect(() => {
    if (!initRef.current) {
      initRef.current = true;
      return;
    }
    if (lastItemRef.current) {
      lastItemRef.current.scrollIntoView({ behavior: 'smooth' });
    }
  }, [metadata.fields.length]);

  useEffect(() => {
    if (errors.metadata && errorRef.current) {
      errorRef.current.scrollIntoView({ behavior: 'smooth' });
    }
  }, [errors.metadata, errorRef]);

  const handleModeChange = (newMode: 'form' | 'json') => {
    if (newMode === 'json' && mode === 'form') {
      // 从表单模式切换到JSON模式，同步数据
      const formData = getValues();
      if (Array.isArray(formData.metadata)) {
        const metadataObj = formData.metadata.reduce((acc: any, x: any) => {
          if (x.key) {
            acc[x.key] = isObjectContent(x.value) ? JSON.parse(x.value) : x.value;
          }
          return acc;
        }, {});
        setJsonValue(JSON.stringify(metadataObj, null, 2));
      }
    }
    setMode(newMode);
  };

  const handleJsonChange = (value: string) => {
    setJsonValue(value);
    // 清除格式化错误状态
    if (formatError) {
      setFormatError(null);
    }
  };

  const handleFormatJson = () => {
    try {
      const parsed = JSON.parse(jsonValue);
      const formatted = JSON.stringify(parsed, null, 2);
      setJsonValue(formatted);
      setFormatError(null);
    } catch (err) {
      setFormatError(err instanceof Error ? err.message : 'Invalid JSON format');
    }
  };

  const toggleBtn = showModeToggle && (
    <Box sx={{ display: 'flex', justifyContent: 'flex-end' }}>
      <Button
        size="small"
        variant="text"
        color="primary"
        sx={{
          color: color === 'inherit' ? 'text.secondary' : 'primary.main',
          minWidth: 'max-content',
        }}
        onClick={() => handleModeChange(mode === 'form' ? 'json' : 'form')}
        startIcon={<Autorenew />}>
        {mode === 'form' ? t('common.metadata.jsonMode') : t('common.metadata.formMode')}
      </Button>
    </Box>
  );
  return (
    <Box sx={{ width: '100%', height: '100%', display: 'flex', flexDirection: 'column' }}>
      {title ? (
        <Stack sx={{ flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center' }}>
          <FormLabel sx={{ color: 'text.primary', my: 0, '& label': { mb: 0 } }}>{title}</FormLabel>
          {toggleBtn}
        </Stack>
      ) : (
        toggleBtn
      )}
      {mode === 'form' ? (
        <>
          <Stack
            sx={{
              maxHeight: {
                xs: showModeToggle ? 'calc(100vh - 180px)' : 'calc(100vh - 130px)',
                md: 400,
              },
              minHeight,
              overflow: 'auto',
              pb: 1.5,
              mr: -1.5,
              pr: 1.5,
              flex: 1,
            }}>
            {metadata.fields.map((meta, index) => (
              <Stack
                key={meta.id}
                ref={index === metadata.fields.length - 1 ? lastItemRef : null}
                sx={{
                  mt: 2,
                  '&:first-child': { mt: 0 },
                  spacing: 2,
                  alignItems: 'flex-end',
                }}
                spacing={2}
                direction="row">
                <Stack
                  direction="row"
                  spacing={2}
                  sx={{ flex: 1, '& > div:first-child': { flex: 1 }, '& > div:last-child': { flex: 2 } }}>
                  <FormInput
                    errorPosition="right"
                    size="small"
                    name={`metadata.${index}.key`}
                    rules={{
                      required: {
                        value: true,
                        message: t('payment.checkout.required'),
                      },
                      validate: (value: any) => {
                        if (value === false || value === 'false') return true;
                        if (!value && value !== 0) return t('payment.checkout.required');
                        return true;
                      },
                      maxLength: {
                        value: 64,
                        message: t('common.maxLength', { len: 40 }),
                      },
                    }}
                    label="Key"
                    placeholder="Key"
                    // @ts-ignore
                    ref={errors?.metadata?.[index]?.key ? errorRef : null}
                    inputProps={{ maxLength: 40 }}
                  />
                  <FormInput
                    size="small"
                    errorPosition="right"
                    name={`metadata.${index}.value`}
                    label="Value"
                    placeholder="Value"
                    rules={{
                      validate: (value: any) => {
                        if (value === false || value === 'false') return true;
                        if (!value && value !== 0) return t('payment.checkout.required');
                        if (typeof value === 'string' && value.length > 256) return t('common.maxLength', { len: 256 });
                        return true;
                      },
                    }}
                    // @ts-ignore
                    ref={errors?.metadata?.[index]?.value ? errorRef : null}
                    inputProps={{ maxLength: 256 }}
                  />
                </Stack>
                <IconButton
                  onClick={() => metadata.remove(index)}
                  sx={{
                    border: '1px solid',
                    borderColor: 'divider',
                    borderRadius: 1,
                    padding: '8px',
                  }}>
                  <DeleteOutlineOutlined color="error" sx={{ opacity: 0.75 }} />
                </IconButton>
              </Stack>
            ))}
          </Stack>

          <Divider />
          <Stack
            direction="row"
            sx={{
              mt: metadata.fields.length ? 2 : 1,
              justifyContent: 'space-between',
            }}>
            <Button
              size="small"
              variant="outlined"
              color="primary"
              sx={{
                color: color === 'inherit' ? 'text.primary' : 'primary.main',
              }}
              onClick={() => metadata.append({ key: '', value: '' })}>
              <AddOutlined fontSize="small" /> {t('common.metadata.add')}
            </Button>
            {actions}
          </Stack>
        </>
      ) : (
        <>
          <TextField
            multiline
            fullWidth
            rows={15}
            value={jsonValue}
            onChange={(e) => handleJsonChange(e.target.value)}
            placeholder={t('common.metadata.jsonPlaceholder')}
            slotProps={{
              input: {
                endAdornment: (
                  <InputAdornment position="end" sx={{ alignSelf: 'flex-start', mt: 1 }}>
                    <Tooltip
                      title={formatError || t('common.metadata.formatJson')}
                      placement="top"
                      slotProps={{
                        tooltip: {
                          sx: {
                            maxWidth: 300,
                            backgroundColor: 'error.main',
                            opacity: 0.8,
                          },
                        },
                      }}>
                      <IconButton
                        onClick={handleFormatJson}
                        size="small"
                        sx={{
                          color: formatError ? 'error.main' : 'text.secondary',
                        }}>
                        <FormatAlignLeft fontSize="small" />
                      </IconButton>
                    </Tooltip>
                  </InputAdornment>
                ),
              },
            }}
            sx={{
              mb: 2,
              mt: 2,
              flex: 1,
              '& .MuiInputBase-input': {
                fontFamily: 'monospace',
                fontSize: '14px',
              },
            }}
          />
          <Divider />
          <Stack direction="row" sx={{ mt: 2, justifyContent: 'flex-end' }}>
            {actions}
          </Stack>
        </>
      )}
    </Box>
  );
}
