import React, {useEffect, useState} from "react"
import {Button, Divider, Empty, Form, PageHeader, Popconfirm, Popover, Row, Space, Tabs, Tag, Tooltip} from "antd"
import {YakScript} from "../invoker/schema"
import {failed, success} from "../../utils/notification"
import {formatTimestamp} from "../../utils/timeUtil"
import {CopyableField, InputItem} from "../../utils/inputUtil"
import {YakEditor} from "../../utils/editors"
import {showDrawer, showModal} from "../../utils/showModal"
import {PluginExecutor} from "./PluginExecutor"
import {DocumentEditor} from "./DocumentEditor"
import MDEditor from "@uiw/react-md-editor"
import {PluginHistoryTable} from "./PluginHistory"
import {openABSFile} from "../../utils/openWebsite"
import {EditOutlined, QuestionOutlined, SettingOutlined} from "@ant-design/icons"
import {BUILDIN_PARAM_NAME_YAKIT_PLUGIN_NAMES, YakScriptCreatorForm} from "../invoker/YakScriptCreator"
import {YakScriptExecResultTable} from "../../components/YakScriptExecResultTable"
import {getValue} from "../../utils/kv";
import {useGetState, useMemoizedFn} from "ahooks";

import "./PluginOperator.css"
import {ResizeBox} from "../../components/ResizeBox";
import {SimplePluginList} from "../../components/SimplePluginList";
import {YakExecutorParam} from "../invoker/YakExecutorParams";

export interface YakScriptOperatorProp {
    yakScriptId: number
    size?: "big" | "small"
    fromMenu?: boolean

    setTrigger?: () => void
    setScript?: (item: any) => any
}

const {ipcRenderer} = window.require("electron")

export const PluginOperator: React.FC<YakScriptOperatorProp> = (props) => {
    const [script, setScript] = useState<YakScript>()
    const [error, setError] = useState("")
    const [loading, setLoading] = useState(false)
    const [groups, setGroups] = useState<string[]>([])
    const [markdown, setMarkdown] = useState("")
    const [trigger, setTrigger] = useState(false)
    const [extraParams, setExtraParams] = useState<YakExecutorParam[]>();
    const [details, setDetails] = useState(true)

    const [settingShow, setSettingShow] = useState<boolean>(false)

    const updateGroups = () => {
        ipcRenderer
            .invoke("QueryGroupsByYakScriptId", {YakScriptId: props.yakScriptId})
            .then((data: { Groups: string[] }) => {
                setGroups(data.Groups)
            })
            .catch((e: any) => {
                console.info(e)
            })
            .finally()
    }

    const update = () => {
        if (props.yakScriptId <= 0) {
            return
        }
        updateGroups()

        setLoading(true)
        ipcRenderer
            .invoke("GetYakScriptById", {Id: props.yakScriptId})
            .then((e: YakScript) => {
                setScript(e)
                // setDetails(!e.IsGeneralModule)

                ipcRenderer
                    .invoke("GetMarkdownDocument", {
                        YakScriptId: e?.Id,
                        YakScriptName: e?.ScriptName
                    })
                    .then((data: { Markdown: string }) => {
                        setMarkdown(data.Markdown)
                    })
                    .catch((e: any) => {
                        setMarkdown("")
                    })
            })
            .catch((e: any) => {
                failed("Query YakScript By ID failed")
            })
            .finally(() =>
                setTimeout(() => {
                    setTrigger(!trigger)
                    setLoading(false)
                }, 300)
            )
    }

    useEffect(() => {
        update()
    }, [props.yakScriptId])

    // 来源于菜单进入以及开启了插件选择的话,就打开
    const enablePluginSelector = (!!script?.EnablePluginSelector) && props.fromMenu;
    const executor = useMemoizedFn(() => {
        return script && (
            <PluginExecutor
                subTitle={
                    <Space>
                        {script.Help && (
                            <Tooltip title={script.Help}>
                                <Button type={"link"} icon={<QuestionOutlined/>}/>
                            </Tooltip>
                        )}
                        <Space size={8}>
                            {/*{script?.ScriptName && (*/}
                            {/*    <Tag>{formatTimestamp(script?.CreatedAt)}</Tag>*/}
                            {/*)}*/}
                            <p style={{color: "#999999", marginBottom: 0}}>作者:{script?.Author}</p>
                            {script?.Tags
                                ? (script?.Tags || "")
                                    .split(",")
                                    .filter((i) => !!i)
                                    .map((i) => {
                                        return (
                                            <Tag
                                                style={{marginLeft: 2, marginRight: 0}}
                                                key={`${i}`}
                                                color={"geekblue"}
                                            >
                                                {i}
                                            </Tag>
                                        )
                                    })
                                : "No Tags"}
                        </Space>
                    </Space>
                }
                extraNode={
                    !props.fromMenu && (
                        <Space>
                            <Tooltip placement='top' title={"插件管理"}>
                                <Button
                                    type={"link"}
                                    icon={<SettingOutlined/>}
                                    onClick={() => setSettingShow(!settingShow)}
                                />
                            </Tooltip>
                            <Tooltip placement='top' title={"编辑插件"}>
                                <Button
                                    type={"link"}
                                    icon={<EditOutlined/>}
                                    style={{color: "#a7a7a7"}}
                                    onClick={(e) => {
                                        let m = showDrawer({
                                            title: `修改插件: ${script?.ScriptName}`,
                                            width: "100%",
                                            content: (
                                                <>
                                                    <YakScriptCreatorForm
                                                        modified={script}
                                                        onChanged={(i) => update()}
                                                        onCreated={() => {
                                                            m.destroy()
                                                        }}
                                                    />
                                                </>
                                            ),
                                            keyboard: false
                                        })
                                    }}
                                />
                            </Tooltip>
                        </Space>
                    )
                }
                script={script}
                size={props.size}
                extraYakExecutorParams={extraParams}
                settingShow={settingShow}
                settingNode={
                    <PluginManagement
                        style={{marginBottom: 10}}
                        script={script}
                        groups={groups}
                        update={() => {
                            setTimeout(() => props.setTrigger!(), 300)
                        }}
                        updateGroups={updateGroups}
                        setScript={props.setScript}
                    />
                }
            />
        )
    })

    const defaultContent = () => {
        return (
            <Tabs className="plugin-store-info" style={{height: "100%"}} type={"card"} defaultValue={"runner"}
                  tabPosition={"right"}>
                <Tabs.TabPane tab={"执行"} key={"runner"}>
                    {!enablePluginSelector && executor()}
                    {enablePluginSelector && <ResizeBox
                        firstNode={<SimplePluginList
                            pluginTypes={script?.PluginSelectorTypes || "mitm,port-scan"}
                            onSelected={names => {
                                setExtraParams([{Key: BUILDIN_PARAM_NAME_YAKIT_PLUGIN_NAMES, Value: names.join("|")}])
                            }}
                        />}
                        firstMinSize={"300px"}
                        firstRatio={"320px"}
                        secondNode={executor()}
                    >

                    </ResizeBox>}
                </Tabs.TabPane>
                <Tabs.TabPane tab={"文档"} key={"docs"}>
                    {script && (
                        <div style={{textAlign: "right", marginBottom: 10}}>
                            <Button
                                onClick={(e) => {
                                    let m = showDrawer({
                                        title: "编辑文档",
                                        keyboard: false,
                                        width: "94%",
                                        onClose: () => {
                                            update()
                                            m.destroy()
                                        },
                                        content: (
                                            <>
                                                <DocumentEditor
                                                    onFinished={() => {
                                                        m.destroy()
                                                    }}
                                                    markdown={markdown}
                                                    yakScript={script}
                                                />
                                            </>
                                        )
                                    })
                                }}
                            >
                                编辑文档
                            </Button>
                        </div>
                    )}
                    {markdown ? (
                        <div>
                            <MDEditor.Markdown source={markdown}/>
                        </div>
                    ) : (
                        <Empty style={{marginTop: 80}} description={"插件作者未添加文档"}/>
                    )}
                </Tabs.TabPane>
                <Tabs.TabPane tab={"源码"} key={"code"}>
                    <div style={{height: "100%"}}>
                        <YakEditor type={script?.Type || "yak"} value={script?.Content} readOnly={true}/>
                    </div>
                </Tabs.TabPane>
                <Tabs.TabPane tab={"历史"} key={"history"}>
                    {script && <PluginHistoryTable script={script} trigger={trigger}/>}
                    {/*<ExecHistoryTable mini={false} trigger={null as any}/>*/}
                </Tabs.TabPane>
                <Tabs.TabPane tab={"结果"} key={"results"}>
                    {script && <YakScriptExecResultTable YakScriptName={script.ScriptName} trigger={trigger}/>}
                </Tabs.TabPane>
            </Tabs>
        )
    }

    const showContent = (module: YakScript): JSX.Element => {
        if (!module) return <></>

        const key = module.GeneralModuleKey

        switch (key) {
            default:
                return defaultContent()
        }
    }

    return <div style={{
        marginLeft: 16,
        height: "100%"
    }}>{!!script && !!props.fromMenu ? showContent(script) : defaultContent()}</div>
}

export interface AddToMenuActionFormProp {
    script: YakScript
    updateGroups?: () => any
}

export const AddToMenuActionForm: React.FC<AddToMenuActionFormProp> = (props) => {
    const {script} = props
    const updateGroups = props?.updateGroups ? props.updateGroups : () => {
    }

    const [params, setParams] = useState<{
        Group: string
        YakScriptId: number
        Verbose: string
    }>({Group: "社区组件", Verbose: props.script.ScriptName, YakScriptId: props.script.Id})

    useEffect(() => {
        setParams({
            Group: "社区组件",
            Verbose: props.script.ScriptName,
            YakScriptId: props.script.Id
        })
    }, [props.script])

    return (
        <div>
            <Form
                size={"small"}
                onSubmitCapture={(e) => {
                    e.preventDefault()

                    if (!script) {
                        failed("No Yak Modeule Selected")
                        return
                    }

                    ipcRenderer
                        .invoke("AddToMenu", params)
                        .then(() => {
                            ipcRenderer.invoke("change-main-menu")
                            updateGroups()
                            success("添加成功")
                        })
                        .catch((e: any) => {
                            failed(`${e}`)
                        })
                }}
            >
                <InputItem
                    label={"菜单选项名(展示名称)"}
                    setValue={(Verbose) => setParams({...params, Verbose})}
                    value={params.Verbose}
                />
                <InputItem
                    label={"菜单分组"}
                    setValue={(Group) => setParams({...params, Group})}
                    value={params.Group}
                />
                <Form.Item colon={false} label={" "}>
                    <Button type='primary' htmlType='submit'>
                        {" "}
                        添加{" "}
                    </Button>
                </Form.Item>
            </Form>
        </div>
    )
}

interface PluginManagementProps {
    script: YakScript
    vertical?: boolean
    update?: () => any
    groups?: string[]
    updateGroups?: () => any
    style?: React.CSSProperties

    setScript?: (item: any) => any
}

export const PluginManagement: React.FC<PluginManagementProps> = React.memo<PluginManagementProps>((props) => {
    const {script, groups, style} = props
    const update = props?.update ? props.update : () => {
    }
    const updateGroups = props?.updateGroups ? props.updateGroups : () => {
    }

    return (
        <Space style={{...style}} direction={props.vertical ? "vertical" : "horizontal"}>
            <Popover
                title={`添加到左侧菜单栏中[${script?.Id}]`}
                content={<>{script && <AddToMenuActionForm script={script} updateGroups={updateGroups}/>}</>}
            >
                <Button size={"small"} type={"primary"} ghost>
                    添加到菜单栏
                </Button>
            </Popover>
            <Button
                size={"small"}
                danger={true}
                onClick={(e) => {
                    let m = showModal({
                        title: "移除菜单栏",
                        content: (
                            <Space direction={"vertical"}>
                                {(groups || []).map((element) => {
                                    return (
                                        <Button
                                            onClick={() => {
                                                ipcRenderer
                                                    .invoke("RemoveFromMenu", {
                                                        YakScriptId: script?.Id,
                                                        Group: element
                                                    })
                                                    .then(() => {
                                                        ipcRenderer.invoke("change-main-menu")
                                                        updateGroups()
                                                        m.destroy()
                                                    })
                                                    .catch((e: any) => {
                                                        console.info(e)
                                                    })
                                                    .finally()
                                            }}
                                        >
                                            从 {element} 中移除
                                        </Button>
                                    )
                                })}
                            </Space>
                        )
                    })
                }}
            >
                移除菜单栏
            </Button>
            {script?.IsIgnore ? (
                <>
                    <Popconfirm
                        title={"取消隐藏该模块?"}
                        onConfirm={() => {
                            ipcRenderer
                                .invoke("UnIgnoreYakScript", {
                                    Id: script?.Id
                                })
                                .then((e) => {
                                    success("显示该模块")
                                })
                                .catch((e: any) => {
                                })
                                .finally(() => {
                                })
                        }}
                    >
                        <Button size={"small"}>取消隐藏 / 取消忽略</Button>
                    </Popconfirm>
                </>
            ) : (
                <Popconfirm
                    title={"忽略该模块将会导致模块在插件仓库不可见,需要在插件仓库中查看"}
                    onConfirm={() => {
                        ipcRenderer
                            .invoke("IgnoreYakScript", {Id: script?.Id})
                            .then((e) => {
                                success("忽略该模块")
                            })
                            .catch((e: any) => {
                            })
                            .finally(() => {
                            })
                    }}
                >
                    <Button size={"small"} danger={true}>
                        不再关注 / 隐藏
                    </Button>
                </Popconfirm>
            )}
            <Button size={"small"} onClick={() => {
                showModal({
                    title: "导出插件配置", width: "40%", content: <>
                        <OutputPluginForm YakScriptId={script.Id}/>
                    </>
                })
            }}>导出插件</Button>
            <Button size={"small"} onClick={() => {
                ipcRenderer.invoke("send-to-tab", {
                    type: "plugin-store",
                    data: {name: script.ScriptName, code: script.Content}
                })
            }}>本地调试</Button>
            <Popconfirm
                title={"确定要删除该插件?如果添加左侧菜单栏也会同步删除,且不可恢复"}
                onConfirm={() => {
                    ipcRenderer.invoke("delete-yak-script", script.Id).then(
                        () => {
                            ipcRenderer.invoke("change-main-menu")
                            if (props.setScript) props.setScript(undefined)
                        })
                    update()
                    // setLoading(true)
                    // setTimeout(() => setTrigger(!trigger), 300)
                }}
            >
                <Button size={"small"} danger={true}>
                    删除插件
                </Button>
            </Popconfirm>
        </Space>
    )
})

export interface OutputPluginFormProp {
    YakScriptId: any
}

export const OutputPluginForm: React.FC<OutputPluginFormProp> = React.memo((props) => {
    const [_, setLocalPath, getLocalPath] = useGetState("");
    const [pluginDirName, setPluginDirName, getPluginDirName] = useGetState("");

    useEffect(() => {
        getValue("YAKIT_DEFAULT_LOAD_LOCAL_PATH").then(e => {
            if (e) {
                setLocalPath(e)
            }
        })
    }, [])

    return <>
        <Form onSubmitCapture={e => {
            e.preventDefault()

            ipcRenderer
                .invoke("ExportYakScript", {
                    YakScriptId: props.YakScriptId,
                    OutputDir: getLocalPath(),
                    OutputPluginDir: getPluginDirName(),
                })
                .then((data: { OutputDir: string }) => {
                    showModal({
                        title: "导出成功!",
                        content: (
                            <>
                                <Space direction={"vertical"}>
                                    <CopyableField text={data.OutputDir}/>
                                    <Button
                                        type={"link"}
                                        onClick={() => {
                                            openABSFile(data.OutputDir)
                                        }}
                                    >
                                        在文件夹中打开
                                    </Button>
                                </Space>
                            </>
                        )
                    })
                })
                .catch((e: any) => {
                    failed(`导出失败: ${e}`)
                })
        }}>
            <InputItem
                label={"本地仓库路径"}
                help={"可在【导出】或仓库配置中配置"}
                value={getLocalPath()}
                setValue={setLocalPath}
                required={true}
            />
            <InputItem
                label={"插件文件夹名"}
                help={"插件文件夹名,尽量精简,无特殊字符"}
                value={getPluginDirName()}
                setValue={setPluginDirName}
                required={true}
            />
            <Form.Item colon={false} label={" "}>
                <Button type="primary" htmlType="submit"> 导出到目标路径 </Button>
            </Form.Item>
        </Form>
    </>
});