import {AutoColumn, AutoText, isNullOrTrue, Message} from "auto-antd";
import {Button, Drawer, Modal, Switch, Table, TableProps} from "antd";
import React, {useEffect, useMemo, useRef, useState} from "react";
import {ColumnsType} from "antd/lib/table";
import {CurdForm, ICurdForm, IProps as IFormProps} from "./Form.tsx";
import {LDAP} from "../../api/ldap.ts";
import {DeleteOutlined, EditOutlined, LoadingOutlined, PlusOutlined, SyncOutlined} from "@ant-design/icons";
import './index.less'
import {ICurdConfig, ICurdData} from "./types.ts";
import {Cell} from "./cell";


export type CurdColumn = AutoColumn & {
    search?: boolean
    editable?: boolean // 编辑时是否可编辑
    hidden?: boolean
    addable?: boolean // 添加时可编辑
    onlyAdd?: boolean // 仅新增时展示
    editHide?: boolean // 编辑时隐藏
    ellipsis?: boolean // 完整显示
}


type PageResp<T> = { total: number, list: T[], current: number, pageSize: number }

type IProps<T> = IFormProps<T> & {
    columns: CurdColumn[],
    getList: (query: any) => Promise<PageResp<T> | undefined>,
    getDetail: (data: Partial<T>, add?: boolean) => Promise<T>
    onDelete?: (data: T) => Promise<any>
    config?: ICurdConfig<T>
    onSuccess?: (data: Partial<T>) => void
    operationRender?: React.ReactNode
    operation?: {
        add?: boolean
        delete?: boolean
    },
    expandable?: TableProps<T>['expandable']
}

/**
 * 一个完成的增删查改界面
 * @constructor
 */
export function CurdPage<T extends ICurdData>(
    {
        columns,
        getList,
        config,
        operationRender,
        onSuccess,
        operation,
        expandable,
        ...props
    }: IProps<T>) {

    const [list, setList] = useState<T[]>([]);
    const [total, setTotal] = useState<number>(0)
    const [query, setQuery] = useState<any>({current: 1, pageSize: 10});
    const [loading, setLoading] = useState<boolean>(false);
    // edit or add
    const [visible, setVisible] = useState<boolean>(false);
    const [editData, setEditData] = useState<Partial<T>>()

    const formRef = useRef<ICurdForm<LDAP.Server>>()

    const onAddOrEdit = (edit: Partial<T>, add?: boolean) => {
        setVisible(true)
        if (props.getDetail) {
            setLoading(true)
            props.getDetail?.(edit,add)
                .then(res => {
                    setEditData(res)
                })
                .catch(err => {
                    Message.warning(err.message)
                    setVisible(false)
                })
                .finally(() => {
                    setLoading(false)
                })
        } else {
            setEditData({...edit})
            setVisible(true)
        }
    }
    const handleDelete = async (edit: T) => {
        Modal.confirm({
            type: 'warning',
            title: '您确定要删除该数据吗？',
            content: '删除操作不可撤销，请谨慎操作',
            onOk: async () => {
                setLoading(true)
                try {
                    await props.onDelete?.(edit)
                    setQuery((q: any)=>({...q}))
                }catch(err: any) {
                    if(err instanceof Error){
                        Message.warning(err.message)
                    }else if (typeof err === "string") {
                        Message.warning(err)
                    }else if (err?.msg) {
                        Message.warning('删除失败，错误信息为：'+ err.msg)
                    }else {
                        Message.warning('删除失败，错误信息为：'+ JSON.stringify(err,null,2))
                    }
                }finally {
                    setLoading(false)
                }
            }
        })
    }


    const tableColumns = useMemo(() => {
        const cols = columns.filter(item => !item.hidden)
            .map((column: CurdColumn) => {
                const col = {
                    ...column,
                    dataIndex: column.key,
                    title: column.title,
                    width: column.width,
                    onCell: (record: Partial<T>) => {
                        return {
                            record,
                            config: column,
                            dataIndex: column.key,
                        }
                    }
                }
                if (col.type == 'switch' && !col.render){
                    col.render = (value: boolean) => <Switch checked={value} disabled/>
                }
                // @ts-ignore
                if (col.type == 'select' && !col.render && column.mode!='tags'){
                    col.render = (value: any) => <AutoText value={value} column={{...col}}/>
                }
                return col;
            }) as ColumnsType<T>
        cols.push({
            dataIndex: "",
            title: "操作",
            width: config?.operationWidth ?? 180,
            render: (_, record, index) => {
                return (<div className="operation-list">
                    {
                        isNullOrTrue(config?.editable) ?
                            (<Button size="small" type="primary" icon={<EditOutlined/>}
                                     onClick={() => onAddOrEdit(record,false)}/>) : null
                    }
                    {
                        operation?.add ? (<Button size="small" type="primary" icon={<PlusOutlined/>}
                                                  onClick={() => onAddOrEdit(record,true)}/>) : null
                    }
                    {
                        operation?.delete ? (<Button size="small" danger={true} icon={<DeleteOutlined/>}
                                                     onClick={() => handleDelete(record)}/>) : null
                    }
                    {config?.operationRender?.(record, index, { handleDelete })}
                </div>)
            }
        })

        return cols;

    }, [columns]);

    const onClose = () => {
        setVisible(false)
        setEditData(undefined)
    }


    useEffect(() => {
        setLoading(true)
        getList(query).then(res => {
            if (res) {
                setList(res.list)
                setTotal(res.total)
            } else {
                Message.warning('无数据！')
            }
        }).finally(() => {
            setLoading(false)
        })
    }, [getList, query]);

    const onPageChange = (current: number, pageSize: number) => {
        setQuery((q: any) => ({...q, current, pageSize}))
    }

    const onSaveSuccess = (data: Partial<T>) => {
        setQuery({...query})
        onSuccess?.(data)
        setVisible(false)
    }

    return <div className="curd">
        <div className="curd-header">
            {
                config?.hideAdd ? null : (<Button onClick={() => onAddOrEdit({},true)} icon={<PlusOutlined/>}/>)
            }
            {operationRender}
            <div style={{flex: 1}}/>
            <Button loading={loading} onClick={() => setQuery({...query})} icon={<SyncOutlined/>}/>
        </div>
        <div className="curd-body">
            <Table columns={tableColumns as any}
                   dataSource={list as any}
                   pagination={ config?.pagination ? {
                       total: total,
                       pageSize: query.pageSize,
                       current: query.current,
                       onChange: onPageChange,
                   }: { pageSize: query.pageSize }}
                   components={{
                       body: {
                           cell: Cell,
                       }
                   }}
                   size="middle"
                   expandable={expandable}
                   bordered={config?.bordered}
                   rowKey={config?.rowKey ?? 'id'}
            />
        </div>
        <div className="curd-footer">

        </div>

        <Drawer open={visible} destroyOnClose width={config?.editDialogWidth ?? 650}
                title={editData?.id ? '编辑' : '新增'}
                height={400} onClose={onClose}>
            <div className="curd-edit-dialog">
                {
                    loading ? (<LoadingOutlined/>) : (
                        <CurdForm ref={formRef as any}
                                  initialData={editData}
                                  columns={columns}
                                  onSave={props.onSave as any}
                                  onSuccess={onSaveSuccess as any}
                                  onClose={onClose}
                                  config={config as any}/>
                    )
                }
            </div>
        </Drawer>

    </div>

}
