import React, { useState, useEffect, useCallback } from 'react'
import { Form, Input, DatePicker, Select, Button, Radio, Switch, Col, Upload, Modal,  InputNumber } from 'antd'
import { Props, FormConfig, Children } from './type'
import style from './index.less'
import moment from 'moment'
import locale from 'antd/es/date-picker/locale/zh_CN';
import { Store } from 'antd/lib/form/interface'
import { UploadOutlined } from '@ant-design/icons'
import 'antd/es/modal/style';
import 'antd/es/slider/style';
import ImgCrop from 'antd-img-crop';
import { useModel } from 'umi'
import { RcFile } from 'antd/lib/upload/interface'
import Demo from '../Cropper'

const { Item } = Form
const { Option } = Select;
const { RangePicker } = DatePicker;
/**
 * 
 * @param props
 * @param {Array} formConfig 必传
 * @param {string} flow 必传 'row' | 'column'
 * @param {string} formFlex 非必传 控制form flex排版方向
 * @param {string} title 非必传 header 标题
 * @param {Function} callback 非必传 传入回调函数执行提交表单后获取表单内的值
 * @param {object} getFormValues 非必传 传入回调函数执行提交表单后获取表单内的值
 * @param {object} labelCol  非必传 改变label的布局
 * @example
 * 按钮配置 htmlType:'submit' 组件上添加submit={callback} 点击按钮可获得所有form表单数据
 * 按钮配置 htmlType:'button' callback:Function 点击按钮可执行回调函数一般用于弹窗之类事件
 * 想要单个select之类组件onChange立即执行发送数据设置formConfig中配置callback
 * 弹窗用getFormSubmit回调拿数据
 * 普通用callback
 * //示例
 *  import Headers from './components/Formitem' //Formitem组件引入
    import { FormConfig } from './components/Formitem/type' //formConfig声明文件
    let formConfig: FormConfig[] = [
        {
            label: 'ID',
            name: 'id',
            tag: 'input',
            placeholder: '请输入ID搜索',
        }
    ]
    const getHeaderValue = (value: object) => {
        console.log(value)
    }
 *  <Headers formConfig={formConfig} formFlex="flex-start" title='Title' submit={getHeaderValue}/>
 */


let Page = React.forwardRef((props: Props, ref) => {
    let { formConfig, formFlex = 'flex-start', title, flow, defaultProps, getFormValues, getFormSubmit, setFormValues, labelCol, ew, isAll, isFirstLeftNull = false } = props
    const [form] = Form.useForm();
    const [lw, setLw] = useState(0)
    const [allValues, setAllValues] = useState<any>()
    const [file, setFile] = useState<any>({})
    const [url, setUrl] = useState<string>('')
    const { dispatch } = useModel('useOperating.useMaterialModal')
    const { set } = useModel(isAll ? 'useOperating.useBdMedia' : 'useOperating.useBdMediaPup')//存放到本地素材状态管理
    const [fileList, setFileList] = useState<any>([])
    const [previewVisible, setPreviewVisible] = useState<boolean>(false)
    const [fileUrl, setFileUrl] = useState<string>('')
    const [wh, setWh] = useState<number>(1 / 1)
    const [cropSize, setCropSize] = useState<any>({ width: 900, height: 383 })

    // useImperativeHandle(ref, () => ({
    //     form
    // }));
    // base64转File
    const dataURLtoFile = (dataurl: any, filename: any) => {
        var arr = dataurl.split(','), mime = arr[0].match(/:(.*?);/)[1],
            bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n);
        while (n--) {
            u8arr[n] = bstr.charCodeAt(n);
        }
        return new File([u8arr], filename, { type: mime });
    }
    //初始化 defaultProps
    const _initDefaultProps = useCallback((name: string, tag: string) => {
        if (defaultProps) {
            if (tag === 'DatePicker' || tag === 'RangePicker') {//处理日期
                if (Array.isArray((defaultProps as any)[name])) {
                    return [moment((defaultProps as any)[name][0]), moment((defaultProps as any)[name][1])]
                }
                return (defaultProps as any)[name] ? moment((defaultProps as any)[name]) : undefined
            }
            if (Array.isArray(defaultProps[name]) && tag === 'select') {//处理多选
                return defaultProps[name].map((n: number) => n.toString())
            }
            return (defaultProps as any)[name]?.toString()
        }
    }, [defaultProps])
    // 提交数据
    const onFinish = useCallback((value: any) => {
        let showTime: boolean = formConfig.some((a: any) => 'showTime' in a && a['showTime'] === true) //判断是否开启了时间表格的显示时分秒
        let Value = JSON.parse(JSON.stringify(value));//深克隆一份value值
        Object.keys(Value).forEach((name: string) => {//对时间进行格式化
            if (Object.prototype.toString.call(value[name]) === '[object Object]') {
                Value[name] = moment(value[name]).format(showTime ? 'YYYY-MM-DD HH:mm:ss' : 'YYYY-MM-DD')
            } else if (Array.isArray(value[name]) && typeof value[name][0] === 'object') {
                Value[name][0] = `${moment(value[name][0]).format(showTime ? 'YYYY-MM-DD HH:mm:ss' : 'YYYY-MM-DD')}`
                Value[name][1] = `${moment(value[name][1]).format(showTime ? 'YYYY-MM-DD HH:mm:ss' : 'YYYY-MM-DD')}`

            }
            if (JSON.stringify(value[name]) === '[]') {
                delete Value[name]
            }
        })
        // submit && submit(Value)

        return Value
    }, [])
    //映射提交
    form.submit = useCallback(() => {
        return () => form.validateFields().then((values: any) => {
            let value = onFinish(values)
            return value
        }).catch((err: any) => console.log(err))
    }, [])
    //设置表单值
    const setValue = useCallback((value: Store) => {
        form.setFieldsValue(value)
    }, [])
    //回调函数获取表单值
    const onValuesChange = useCallback((changedValues: any, allValues: any) => {
        getFormValues && getFormValues({ changedValues, allValues })//如若父组件设置了getFormValues可实时获取表单输入的值
        setAllValues(allValues)
    }, [getFormValues])
    //输入搜索的回调
    const onSelect = useCallback((value: any, callback?: Function) => {
        callback ? callback(value) : console.log('没有在headerConfig中配置对应的回调函数', value)

    }, [])
    const onRadio = (value: any) => {

    }
    //select按钮回调
    const onChange = useCallback((value: string | string[], change?: boolean, callback?: (v: any) => void) => {
        callback && callback(value)
    }, [])
    //文件上传获取
    const fileChanage = useCallback((e: any) => {
        try {
            let file = e?.target?.files || e
            console.log(file)
            setValue({ 'file': 'true' })
            dispatch({ type: 'file', params: { file: file[0] || file } })
            set({ file: file[0] || file })
            if (file) {
                setFile(file[0] || file)
            }
        } catch (err) {
            console.log(err)
        }
    }, [])
    useEffect(() => {
        getFormSubmit && getFormSubmit(form.submit)//如若父组件设置了getFormSubmit将submit方法传给父组件回调
        setFormValues && setFormValues(setValue)//如若父组件设置了getFormSubmit将setValue方法传给父组件
    }, [])
    //默认的错误提示信息
    const validateMessages = {
        required: "'${name}' 是必选字段",
        // ...
    };
    //预览
    const preview = useCallback(() => {
        let type = file.type.split('/')[0]
        switch (type) {
            case 'audio':
                return <audio src={url} controls />
            case 'video':
                return <video src={url} controls />
            case 'image':
                return <img src={url} width='150' />
            default:
                return null
        }
    }, [file, url])
    //上传字典
    let fileType: any = {
        '上传图片': 'image/gif,image/jpeg,image/png,image/jpg',
        '上传视频': 'video/*',
        '上传音频': 'audio/*',
        '上传Excel': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel'
    }
    return <div className={`${style.form_style} ${isFirstLeftNull && style.form_styleNull}`}>
        <h1>{title}</h1>
        <Form
            form={form}
            onFinish={onFinish}
            style={flow === 'row' ? { justifyContent: formFlex, flexFlow: 'row wrap' } : { justifyContent: formFlex, flexFlow: 'column', alignItems: formFlex }}
            onValuesChange={onValuesChange}
            validateMessages={validateMessages}
        // ref={fromEl}
        >
            {
                formConfig.map((obj: FormConfig, index: number) => {
                    let { Rule, name, tag, label, placeholder, disabled = false, btnType, htmlType, showTime, tagProps, mode, children, width, textSwitch, callback, icon, required, message = '请输入', defaultValue, rows, copy, change, isShowUp = true, formatter, parser } = obj
                    if (label) {
                        label.length > lw && setLw(label.length)
                    }
                    let objWidth: React.CSSProperties | undefined = width ? { minWidth: `${width}px`, float: 'left' } : undefined
                    let Tag: JSX.Element = <></>
                    switch (tag) {
                        case 'input':
                            Tag = <Input placeholder={placeholder} disabled={disabled} {...tagProps} allowClear style={objWidth} onBlur={callback} />
                            break;
                        case 'inputNumber':
                            Tag = <InputNumber placeholder={placeholder} disabled={disabled} {...tagProps} formatter={formatter} parser={parser} style={objWidth ? objWidth : { width: "100%" }} onBlur={callback} />
                            break;
                        case 'inputFile':
                            Tag = <>
                                <div className={style.file}>
                                    <Button type='primary'><UploadOutlined />{label === "上传Excel" ? "导入" : "上传文件"}</Button>
                                    <input type='file' onChange={fileChanage} accept={fileType[(label as string)]} />
                                </div>
                                {
                                    isShowUp && <>
                                        <p>{file?.name}</p>
                                        {
                                            file?.name && preview()
                                        }
                                    </>
                                }

                            </>
                            break;
                        case 'imgCrop':
                            Tag = <>
                                <div style={{ display: 'flex' }}>
                                    <ImgCrop
                                        rotate
                                        aspect={1 / 1}
                                    >
                                        <Upload
                                            listType="picture-card"
                                            accept='image/gif,image/jpeg,image/png,image/jpg'
                                            beforeUpload={function (file: RcFile) {
                                                fileChanage(file)
                                                return false
                                            }}
                                            fileList={fileList}
                                            onChange={(newFileList: any) => {
                                                setFileList([...newFileList.fileList])
                                            }}
                                            onPreview={(file: any) => {
                                                setPreviewVisible(true)
                                                setFileUrl(file.thumbUrl)
                                            }}
                                        >
                                            {fileList?.length < 1 && '1:1裁剪上传'}
                                        </Upload>
                                    </ImgCrop>
                                    {
                                        fileList?.length < 1 && <ImgCrop
                                            rotate
                                            aspect={2.35 / 1}
                                        >
                                            <Upload
                                                listType="picture-card"
                                                accept='image/gif,image/jpeg,image/png,image/jpg'
                                                beforeUpload={function (file: RcFile) {
                                                    fileChanage(file)
                                                    return false
                                                }}
                                                fileList={fileList}
                                                onChange={(newFileList: any) => {
                                                    console.log(newFileList)
                                                    setFileList([...newFileList.fileList])
                                                }}
                                                onPreview={(file: any) => {
                                                    setPreviewVisible(true)
                                                    setFileUrl(file.thumbUrl)
                                                }}
                                            >
                                                {fileList?.length < 1 && '2.35:1裁剪上传'}
                                            </Upload>
                                        </ImgCrop>
                                    }
                                    {
                                        fileList?.length < 1 && <Upload
                                            listType="picture-card"
                                            accept='image/gif,image/jpeg,image/png,image/jpg'
                                            beforeUpload={function (file: RcFile) {
                                                fileChanage(file)
                                                return false
                                            }}
                                            fileList={fileList}
                                            onChange={(newFileList: any) => {
                                                setFileList([...newFileList.fileList])
                                            }}
                                            onPreview={(file: any) => {
                                                setPreviewVisible(true)
                                                setFileUrl(file.thumbUrl)
                                            }}
                                        >
                                            {fileList?.length < 1 && '普通上传'}
                                        </Upload>
                                    }
                                </div>
                                {
                                    fileList?.length < 1 && <div style={{ height: 80 }}>
                                        <Demo width={1080} height={864} callback={(imgData: any) => {
                                            let file = dataURLtoFile(imgData, Math.round(new Date() as any / 1000))
                                            fileChanage(file)
                                            setFileList([{
                                                uid: Math.random() * 100,
                                                thumbUrl: imgData
                                            }])
                                        }} btnName={<div style={{ display: 'flex', flexFlow: 'column', alignItems: 'center', justifyContent: 'center' }}>
                                            <span>自定义裁剪可自行设置准确宽高</span>
                                            <strong style={{ color: 'red' }}>默认：微信卡片图片1080*864</strong>
                                        </div>} />
                                    </div>
                                }
                                <Modal
                                    visible={previewVisible}
                                    footer={null}
                                    onCancel={() => {
                                        setPreviewVisible(false)
                                    }}
                                >
                                    <img alt="example" style={{ width: '100%' }} src={fileUrl} />
                                </Modal>
                            </>
                            break;
                        case 'inputSearch':
                            Tag = <Input.Search placeholder={placeholder} disabled={disabled} {...tagProps} allowClear style={objWidth} onSearch={value => onSelect(value, callback)} enterButton />
                            break;
                        case 'button':
                            Tag = <Button type={btnType} htmlType={htmlType} {...tagProps} style={objWidth} onClick={htmlType === 'button' ? callback : undefined} icon={icon}>{label}</Button>
                            break;
                        case 'DatePicker':
                            Tag = <DatePicker showTime={showTime} {...tagProps} autoComplete='off' locale={locale} style={objWidth} />
                            break;
                        case 'RangePicker':
                            Tag = <RangePicker autoComplete='off' showTime={showTime} {...tagProps} locale={locale} style={objWidth} />
                            break;
                        case 'switch':
                            Tag = <Switch checkedChildren={textSwitch ? textSwitch[0] : "开"} unCheckedChildren={textSwitch ? textSwitch[1] : "关"} defaultChecked {...tagProps} />
                            break;
                        case 'select':
                            Tag = <Select
                                {...tagProps}
                                showSearch
                                allowClear
                                mode={mode}
                                disabled={disabled} // Object.keys(defaultProps || {}).length !== 0 判断是否添加
                                placeholder={placeholder}
                                onChange={(value: string | string[]) => onChange(value, change, callback)}
                                filterOption={(input: string, option: any) => {
                                    return option.children.toLowerCase().indexOf(input.toLowerCase()) >= 0
                                }}
                                optionFilterProp="children"
                                style={objWidth}
                            >
                                {
                                    children && children.map((a: Children) => {
                                        return <Option value={`${a.value}`} key={`${a.value}` as string}>{a.text}</Option>
                                    })
                                }
                            </Select>
                            break;
                        case 'radio':
                            Tag = <Radio.Group onChange={onRadio} {...tagProps}>
                                {
                                    children && children.map((a: Children) => {
                                        return <Radio value={a.value} key={a.value as string}>{a.text}</Radio>
                                    })
                                }
                            </Radio.Group>
                            break;
                        case 'TextArea':
                            Tag = <Input.TextArea rows={rows} style={{ ...objWidth, marginBottom: '10px' }} placeholder={placeholder} />

                            {/* <p onClick={() => { callback && callback(copy) }}>{copy}</p> */ }
                            break;
                    }
                    return <Col key={index + 'i'} flex={flow !== 'row' ? 1 : undefined} className={ew ? style.form_row : undefined}>
                        <Item
                            name={tag !== 'button' ? name : undefined}//假如是按钮那就不需要name属性
                            label={tag !== 'button' ? label : undefined}//假如是按钮就不需要label
                            style={tag === 'button' ? undefined : { minWidth: '200px' }}
                            // normalize={(value, prevValue, prevValues) => value }
                            className={flow !== 'row' ? `${style[`form_item${lw}`]}` : undefined}
                            initialValue={_initDefaultProps(name, tag) || (tag === 'DatePicker' ? defaultValue ? moment(defaultValue as string, 'YYYY/MM/DD') : undefined : defaultValue)}//默认值
                            rules={required ? [{ required: required, message }, { ...Rule }] : []}
                            colon={true}
                            labelCol={labelCol ? labelCol : {}}
                        >
                            {Tag}
                        </Item>
                    </Col>
                })
            }
        </Form>
    </div >
})


export default Page