import React, { Component } from 'react'
import {
    Button,
    Card,
    Form,
    Input,
    message as Message,
    Popconfirm,
    Select,
    Tag,
    Tooltip,
    Upload,
} from 'antd'
import { AntIcon, Auth, Container, PhotoPreview, QueryTable, QueryTableActions } from 'components'
import { api } from 'common/api'
import auth from 'components/authorized/handler'
import { isEqual } from 'lodash'
import getDictData from 'util/dic'
import { toCamelCase } from 'util/format'
import { ArrayBufferToBase64, GetFileName, PreviewFileArrayBuffer } from 'util/file'

/**
 * 注释段[\/**\/]为必须要改
 */

/**
 * 配置页面所需接口函数
 */
const apiAction = {
    page: api.sysFileInfoPage,
    delete: api.sysFileInfoDelete,
}

/**
 * 用于弹窗标题
 * [必要]
 */
const name = '/**/'

/**
 * 统一配置权限标识
 * [必要]
 */
const authName = 'sysFileInfo'

export default class index extends Component {
    state = {
        codes: {
            fileStorageLocation: [],
        },

        uploading: false,
    }

    // 表格实例
    table = React.createRef()

    photoPreview = React.createRef()

    columns = [
        {
            title: '文件名称',
            dataIndex: 'fileOriginName',
            width: 300,
            ellipsis: {
                showTitle: false,
            },
            sorter: true,
            render: text => <Tooltip title={text}>{text}</Tooltip>,
        },
        {
            title: '文件后缀',
            dataIndex: 'fileSuffix',
            width: 120,
            sorter: true,
            render: text => <Tag color="green">{text}</Tag>,
        },
        {
            title: '文件大小',
            dataIndex: 'fileSizeKb',
            width: 120,
            sorter: true,
            render: text => (
                <>
                    {text}
                    <small>KB</small>
                </>
            ),
        },
        {
            title: '存储位置',
            dataIndex: 'fileLocation',
            width: 120,
            sorter: true,
            render: text => this.bindCodeValue(text, 'file_storage_location'),
        },
        {
            title: '文件仓库',
            dataIndex: 'fileBucket',
            width: 200,
            ellipsis: {
                showTitle: false,
            },
            sorter: true,
            render: text => <Tooltip title={text}>{text}</Tooltip>,
        },
        {
            title: '唯一标识id',
            dataIndex: 'fileObjectName',
            width: 250,
            ellipsis: {
                showTitle: false,
            },
            sorter: true,
            render: text => <Tooltip title={text}>{text}</Tooltip>,
        },
        {
            title: '上传时间',
            dataIndex: 'createdTime',
            width: 200,
            sorter: true,
            defaultSortOrder: 'descend',
        },
    ]

    /**
     * 构造函数,在渲染前动态添加操作字段等
     * @param {*} props
     */
    constructor(props) {
        super(props)

        const flag = auth({ [authName]: 'delete' })

        if (flag) {
            this.columns.push({
                title: '操作',
                width: 150,
                dataIndex: 'actions',
                render: (text, record) => (
                    <QueryTableActions>
                        <a onClick={() => this.onFileDownload(record)}>下载</a>
                        <Auth auth={{ [authName]: 'delete' }}>
                            <Popconfirm
                                placement="topRight"
                                title="是否确认删除"
                                onConfirm={() => this.onDelete(record)}
                            >
                                <a>删除</a>
                            </Popconfirm>
                        </Auth>
                        {['png', 'jpeg', 'jpg', 'gif', 'tif', 'bmp'].includes(
                            record.fileSuffix
                        ) && <a onClick={() => this.onFilePreview(record)}>预览</a>}
                    </QueryTableActions>
                ),
            })
        }
    }

    /**
     * 阻止外部组件引发的渲染,提升性能
     * 可自行添加渲染条件
     * [必要]
     * @param {*} props
     * @param {*} state
     * @returns
     */
    shouldComponentUpdate(props, state) {
        return !isEqual(this.state, state)
    }

    /**
     * 加载字典数据,之后开始加载表格数据
     * 如果必须要加载字典数据,可直接对表格设置autoLoad=true
     */
    componentDidMount() {
        const { onLoading, onLoadData } = this.table.current
        onLoading()
        getDictData('file_storage_location').then(codes => {
            this.setState({ codes }, () => {
                onLoadData()
            })
        })
    }

    /**
     * 调用加载数据接口,可在调用前对query进行处理
     * [异步,必要]
     * @param {*} params
     * @param {*} query
     * @returns
     */
    loadData = async (params, query) => {
        const { data } = await apiAction.page({
            ...params,
            ...query,
        })
        return data
    }

    /**
     * 绑定字典数据
     * @param {*} code
     * @param {*} name
     * @returns
     */
    bindCodeValue(code, name) {
        name = toCamelCase(name)
        const codes = this.state.codes[name]
        if (codes) {
            const c = codes.find(p => p.code == code)
            if (c) {
                return c.value
            }
        }
        return null
    }

    /**
     * 打开新增/编辑弹窗
     * @param {*} modal
     * @param {*} record
     */
    onOpen(modal, record) {
        modal.current.open({
            record,
        })
    }

    /**
     * 对表格上的操作进行统一处理
     * [异步]
     * @param {*} action
     * @param {*} successMessage
     */
    async onAction(action, successMessage) {
        const { onLoading, onLoaded, onReloadData } = this.table.current
        onLoading()
        try {
            if (action) {
                await action
            }
            if (successMessage) {
                Message.success(successMessage)
            }
            onReloadData()
        } catch {
            onLoaded()
        }
    }

    /**
     * 删除
     * @param {*} record
     */
    onDelete(record) {
        this.onAction(apiAction.delete(record), '删除成功')
    }

    //#region 自定义方法
    async onFileUpload({ file }) {
        this.setState({ uploading: true })
        const table = this.table.current
        table.onLoading()
        const fd = new FormData()
        fd.append('file', file)
        try {
            await api.sysFileInfoUpload(fd)
            table.onReloadData()
        } catch {
            table.onLoaded()
        } finally {
            this.setState({ uploading: false })
        }
    }

    async onFilePreview({ id }) {
        const key = Math.random().toString(16).slice(2)
        const hide = Message.loading({
            key,
            content: '正在获取文件...',
            duration: 0,
        })
        const file = await PreviewFileArrayBuffer(id)
        if (file) {
            const base64 = await ArrayBufferToBase64(file)
            var img = new Image()
            img.onload = () => {
                const items = [
                    {
                        src: base64,
                        w: img.naturalWidth,
                        h: img.naturalHeight,
                    },
                ]
                this.photoPreview.current.initPhotoSwipe(items)

                hide()
            }
            img.onerror = () => {
                Message.error({
                    key,
                    content: '获取文件失败',
                })
            }
            img.src = base64
        } else {
            Message.error({
                key,
                content: '获取文件失败',
            })
        }
    }

    async onFileDownload({ id }) {
        const key = Math.random().toString(16).slice(2)
        const hide = Message.loading({
            key,
            content: '正在获取文件...',
            duration: 0,
        })
        try {
            const { data, headers } = await api.sysFileInfoDownload({ id })
            const url = window.URL.createObjectURL(data)
            const fileName = GetFileName(headers['content-disposition'])
            const a = document.createElement('a')
            a.href = url
            a.download = fileName
            a.click()
            window.URL.revokeObjectURL(url)
            a.remove()
            hide()
        } catch {
            Message.error({
                key,
                content: '下载文件失败',
            })
        }
    }
    //#endregion

    render() {
        const { codes, uploading } = this.state

        return (
            <Container mode="fluid">
                <br />
                <Card bordered={false}>
                    <QueryTable
                        ref={this.table}
                        autoLoad={false}
                        loadData={this.loadData}
                        columns={this.columns}
                        query={
                            <Auth auth={{ [authName]: 'page' }}>
                                <Form.Item label="文件名" name="fileOriginName">
                                    <Input
                                        autoComplete="off"
                                        placeholder="请输入文件名"
                                        className="w-200"
                                    />
                                </Form.Item>
                                <Form.Item label="存储位置" name="fileLocation">
                                    <Select placeholder="请选择存储位置" className="w-200">
                                        {codes.fileStorageLocation.map(item => (
                                            <Select.Option key={item.code} value={item.code}>
                                                {item.value}
                                            </Select.Option>
                                        ))}
                                    </Select>
                                </Form.Item>
                                <Form.Item label="文件仓库" name="fileBucket">
                                    <Input
                                        autoComplete="off"
                                        placeholder="请输入文件仓库"
                                        className="w-200"
                                    />
                                </Form.Item>
                            </Auth>
                        }
                        operator={
                            <Auth auth={{ [authName]: 'add' }}>
                                <Upload customRequest={e => this.onFileUpload(e)} fileList={[]}>
                                    <Button loading={uploading} icon={<AntIcon type="upload" />}>
                                        上传文件
                                    </Button>
                                </Upload>
                            </Auth>
                        }
                    />
                </Card>

                <PhotoPreview ref={this.photoPreview} />
            </Container>
        )
    }
}
