import axios from 'axios';
import React, { FunctionComponent, useCallback, useEffect, useState } from "react";
import { Button } from '@revoltchat/ui/lib/components/atoms/inputs/Button';
import { InputBox } from '@revoltchat/ui/lib/components/atoms/inputs/InputBox';
import { Checkbox } from '@revoltchat/ui/lib/components/atoms/inputs/Checkbox';
import { ComboBox } from '@revoltchat/ui/lib/components/atoms/inputs/ComboBox';
import { LineDivider } from '@revoltchat/ui/lib/components/atoms/layout/LineDivider';
import { H1 } from '@revoltchat/ui/lib/components/atoms/heading/H1';
import { H3 } from '@revoltchat/ui/lib/components/atoms/heading/H3';
import { H4 } from '@revoltchat/ui/lib/components/atoms/heading/H4';
import { Icon } from '@mdi/react';
import { mdiChevronLeft, mdiCloseBox } from '@mdi/js';
import { API_URL } from "../../App";
import { getAuthHeaders } from "../../utils";
import { Link, useParams } from "react-router-dom";
import defaultChannelIcon from '../../assets/channel-default-icon.svg';
import CategorySelector from '../../components/CategorySelector';

type User = { id: string, username?: string, avatarURL?: string }
type Channel = { id: string, name: string, icon?: string, type: 'VOICE'|'TEXT', nsfw: boolean }

type Server = {
    id?: string,
    perms?: 0|1|2|3,
    name?: string,
    description?: string,
    iconURL?: string,
    bannerURL?: string,
    serverConfig?: { [key: string]: any },
    users: User[],
    channels: Channel[],
}

type AntispamRule = {
    id: string;
    max_msg: number;
    timeframe: number;
    action: 0|1|2|3|4;
    channels: string[] | null;
    message: string | null;
}

const ServerDashboard: FunctionComponent = () => {
    const [category, setCategory] = useState('home');

    const [serverInfo, setServerInfo] = useState({} as Server);
    const [status, setStatus] = useState('');

    const [changed, setChanged] = useState({} as { prefix?: boolean, prefixAllowSpace?: boolean });
    const [prefix, setPrefix] = useState('' as string|undefined);
    const [prefixAllowSpace, setPrefixAllowSpace] = useState(false);
    
    const [botManagers, setBotManagers] = useState([] as string[]);
    const [moderators, setModerators] = useState([] as string[]);

    const [automodSettings, setAutomodSettings] = useState(null as { antispam: AntispamRule[] }|null);

    const { serverid } = useParams();

    const saveConfig = useCallback(async () => {
        if (Object.values(changed).filter(i => i).length == 0) return;

        const payload = {
            ...(changed.prefix ? { prefix } : undefined),
            ...(changed.prefixAllowSpace ? { spaceAfterPrefix: prefixAllowSpace } : undefined),
        }

        const res = await axios.put(
            API_URL + `/dash/server/${serverid}/config`,
            payload,
            { headers: await getAuthHeaders() }
        );

        if (res.data.success) {
            setChanged({});
        }
    }, [ prefix, prefixAllowSpace, changed ]);

    const loadInfo = useCallback(async () => {
        try {
            const res = await axios.get(`${API_URL}/dash/server/${serverid}`, { headers: await getAuthHeaders() });
            console.log(res.data);

            const server: Server = res.data.server;
            setServerInfo(server);

            setPrefix(server.serverConfig?.prefix || '');
            setPrefixAllowSpace(!!server.serverConfig?.spaceAfterPrefix);

            setBotManagers(server.serverConfig?.botManagers ?? []);
            setModerators(server.serverConfig?.moderators ?? []);

            loadAutomodInfo(server);
        } catch(e: any) {
            console.error(e);
            setStatus(`${e?.message ?? e}`);
        }
    }, [serverInfo]);

    const loadAutomodInfo = useCallback(async (server: Server) => {
        if ((server.perms ?? 0) > 0) {
            const res = await axios.get(API_URL + `/dash/server/${serverid}/automod`, { headers: await getAuthHeaders() });
            setAutomodSettings(res.data);
            console.log(res.data);
        }
    }, []);

    useEffect(() => {
        loadInfo();
    }, []);

    return (
        <>
            {status.length ? <a>{status}</a> : <></>}
            <div
                style={{
                    marginTop: '8px',
                    marginLeft: '8px',
                    textOverflow: 'ellipsis',
                    whiteSpace: 'nowrap',
                    overflow: 'hidden',
                    color: 'var(--secondary-foreground)',
                    maxWidth: 'calc(100% - 20px)',
                }}
            >
                <Link to='/dashboard' style={{ float: 'left' }}>
                    <div style={{ display: 'flex' }}>
                        <Icon path={mdiChevronLeft} style={{ height: '25px' }} />
                        <span>Back</span>
                    </div>
                </Link>
                <span
                    style={{
                        color: 'var(--foreground)',
                        marginLeft: '8px',
                    }}
                >
                    {serverInfo?.name ?? 'Loading...'}
                </span>
                <span style={{ color: 'var(--secondary-foreground)', marginLeft: '6px' }}>
                    •
                </span>
                <span
                    style={{
                        color: 'var(--secondary-foreground)',
                        marginLeft: '6px',
                    }}
                >
                    {serverInfo.description || <i>No server description set</i>}
                </span>
            </div>

            <CategorySelector
                keys={[
                    { id: 'home', name: 'Home' },
                    { id: 'automod', name: 'Moderation Rules' },
                ]}
                selected={category}
                onChange={setCategory}
                />

            <div hidden={Object.keys(serverInfo).length == 0}>
                <div style={{ paddingLeft: '10px', paddingRight: '10px' }}>

                    {category == 'home' && (
                        <>
                            <>
                                <H3>Prefix</H3>
                                <InputBox
                                    style={{ width: '150px', }}
                                    placeholder="Enter a prefix..."
                                    value={prefix}
                                    onChange={e => {
                                        setPrefix(e.currentTarget.value);
                                        setChanged({ ...changed, prefix: true });
                                    }}
                                />
                                <Checkbox
                                    style={{ maxWidth: '400px' }}
                                    value={prefixAllowSpace}
                                    onChange={() => {
                                        setPrefixAllowSpace(!prefixAllowSpace);
                                        setChanged({ ...changed, prefixAllowSpace: true });
                                    }}
                                    title="Allow space after prefix"
                                    description={'Whether the bot recognizes a command if the prefix is followed by a space. Enable if your prefix is a word.'}
                                />
                                <Button
                                    style={{ marginTop: "16px" }}
                                    onClick={saveConfig}
                                >Save</Button>
                            </>

                            <LineDivider />

                            <>
                                <H3>Bot Managers</H3>
                                <H4>
                                    Only users with "Manage Server" permission are allowed to add/remove other
                                    bot managers and are automatically considered bot manager.
                                </H4>
                                <UserListTypeContainer>
                                    <UserListContainer disabled={(serverInfo.perms ?? 0) < 3}>
                                        {botManagers.map((uid: string) => {
                                            const user = serverInfo.users.find(u => u.id == uid) || { id: uid }
                                            return (
                                                <UserListEntry type='MANAGER' user={user} key={uid} />
                                            )})}
                                        <UserListAddField type='MANAGER' />
                                    </UserListContainer>
                                </UserListTypeContainer>

                                <H3>Moderators</H3>
                                <H4>
                                    Only bot managers are allowed to add/remove moderators.
                                    All bot managers are also moderators.
                                </H4>
                                <UserListTypeContainer>
                                    <UserListContainer disabled={(serverInfo.perms ?? 0) < 2}>
                                        {moderators.map((uid: string) => {
                                            const user = serverInfo.users.find(u => u.id == uid) || { id: uid }
                                            return (
                                                <UserListEntry type='MOD' user={user} key={uid} />
                                            )})}
                                        <UserListAddField type='MOD' />
                                    </UserListContainer>
                                </UserListTypeContainer>
                            </>
                        </>
                    )}

                    {category == 'automod' && (
                        <>
                            <H3>Antispam Rules</H3>
                            {serverInfo.perms != null && automodSettings && (
                                serverInfo.perms > 0
                                    ? (
                                        <>
                                            {automodSettings.antispam.map((r, i) => (
                                                <>
                                                    <AntispamRule rule={r} key={r.id} />
                                                    {i < automodSettings.antispam.length - 1 && <LineDivider/>}
                                                </>
                                            ))}
                                            <Button style={{
                                                marginTop: '12px',
                                                marginBottom: '8px',
                                            }} onClick={async () => {
                                                const newRule: AntispamRule = {
                                                    action: 0,
                                                    max_msg: 5,
                                                    timeframe: 3,
                                                    message: null,
                                                    id: '',
                                                    channels: [],
                                                }

                                                const res = await axios.post(
                                                    `${API_URL}/dash/server/${serverid}/automod`,
                                                    {
                                                        action: newRule.action,
                                                        max_msg: newRule.max_msg,
                                                        timeframe: newRule.timeframe,
                                                    },
                                                    { headers: await getAuthHeaders() }
                                                );

                                                newRule.id = res.data.id;

                                                setAutomodSettings({ antispam: [ ...(automodSettings.antispam), newRule ] });
                                            }}>
                                                Create Rule
                                            </Button>
                                        </>
                                    )
                                    : (
                                        <div>
                                            <p style={{ color: 'var(--foreground)' }}>
                                                You do not have access to this.
                                            </p>
                                        </div>
                                    )
                                )
                            }
                        </>
                    )}
                </div>
            </div>
        </>
    );

    function RemoveButton(props: { onClick: () => void }) {
        return (
            <div
                style={{
                    marginLeft: '4px',
                    verticalAlign: 'middle',
                    display: 'inline-block',
                    height: '30px',
                }}
                onClick={props.onClick}
            >
                <Icon  // todo: hover effect
                    path={mdiCloseBox}
                    color='var(--tertiary-foreground)'
                    size='30px'
                />
            </div>
        )
    }

    function UserListEntry(props: { user: User, type: 'MANAGER'|'MOD' }) {
        return (
            <div
                key={props.user.id}
                style={{
                    display: 'block',
                    margin: '4px 6px',
                    padding: '4px',
                    backgroundColor: 'var(--tertiary-background)',
                    borderRadius: '5px',
                }}
            >
                <img
                    src={props.user.avatarURL ?? 'https://amogus.org/amogus.png'}
                    width={28}
                    height={28}
                    style={{
                        borderRadius: '50%',
                        verticalAlign: 'middle',
                        display: 'inline-block',
                    }}
                />
                <span
                    style={{
                        color: 'var(--foreground)',
                        fontSize: '20px',
                        paddingLeft: '6px',
                        marginBottom: '2px',
                        verticalAlign: 'middle',
                        display: 'inline-block',
                    }}
                >{props.user.username ?? 'Unknown'}</span>
                <RemoveButton
                    onClick={async () => {
                        const res = await axios.delete(
                            `${API_URL}/dash/server/${serverid}/${props.type == 'MANAGER' ? 'managers' : 'mods'}/${props.user.id}`,
                            { headers: await getAuthHeaders() }
                        );

                        if (props.type == 'MANAGER') {
                            setBotManagers(res.data.managers);
                        }
                        else if (props.type == 'MOD') {
                            setModerators(res.data.mods);
                        }
                    }}
                />
            </div>
        );
    }

    function UserListContainer(props: { disabled: boolean, children: any }) {
        return (
            <div
                style={{
                    display: 'flex',
                    flexWrap: 'wrap',
                    ...(props.disabled ? {
                        filter: 'grayscale(100%)',
                        pointerEvents: 'none',
                    } : {})
                }}
            >
                {props.children}
            </div>
        );
    }

    function UserListTypeContainer(props: any) {
        return (
            <div
                style={{
                    display: 'flex',
                    backgroundColor: 'var(--secondary-background)',
                    borderRadius: '10px',
                    marginTop: '15px',
                    paddingTop: '5px',
                    paddingBottom: '5px',
                }}
            >{props.children}</div>
        );
    }

    function UserListAddField(props: { type: 'MANAGER'|'MOD' }) {
        const [content, setContent] = useState('');

        const onConfirm = useCallback(async () => {0
            if (content.length) {
                const res = await axios.put(
                    `${API_URL}/dash/server/${serverid}/${props.type == 'MANAGER' ? 'managers' : 'mods'}`,
                    { item: content },
                    { headers: await getAuthHeaders() }
                );

                if (res.data.users?.length) {
                    res.data.users.forEach((user: User) => {
                        if (!serverInfo.users.find(u => u.id == user.id)) serverInfo.users.push(user);
                    });
                }

                if (props.type == 'MANAGER') {
                    setBotManagers(res.data.managers);
                }
                else if (props.type == 'MOD') {
                    setModerators(res.data.mods);
                }
            }
        }, [content]);

        return (
            <div>
                <InputBox
                    placeholder={`Add a ${props.type == 'MANAGER' ? 'bot manager' : 'moderator'}...`}
                    value={content}
                    onChange={e => setContent(e.currentTarget.value)}
                    style={{
                        float: 'left',
                        width: '180px',
                        height: '38px',
                        margin: '4px 8px',
                    }}
                    onKeyDown={e => e.key == 'Enter' && onConfirm()}
                />
                <Button
                    style={{
                        float: 'left',
                        width: '40px',
                        height: '38px',
                        margin: '4px 8px',
                        opacity: content.length > 0 ? '1' : '0',
                    }}
                    onClick={onConfirm}
                >Ok</Button>
            </div>
        );
    }

    function ChannelListAddField(props: { onInput: (channel: Channel) => void }) {
        const [content, setContent] = useState('');

        const onConfirm = useCallback(async () => {
            if (content.length) {
                const channel = serverInfo.channels
                    .find(c => c.id == content.toUpperCase())
                    || serverInfo.channels
                    .find(c => c.name == content)
                    || serverInfo.channels                                     // Prefer channel with same capitalization,
                    .find(c => c.name.toLowerCase() == content.toLowerCase()); // otherwise search case insensitive

                if (channel && channel.type == 'TEXT') {
                    props.onInput(channel);
                    setContent('');
                }
            }
        }, [content]);

        return (
            <div>
                <InputBox
                    placeholder={`Add a channel...`}
                    value={content}
                    onChange={e => setContent(e.currentTarget.value)}
                    style={{
                        float: 'left',
                        width: '180px',
                        height: '38px',
                        margin: '4px 8px',
                    }}
                    onKeyDown={e => e.key == 'Enter' && onConfirm()}
                />
                <Button
                    style={{
                        float: 'left',
                        width: '40px',
                        height: '38px',
                        margin: '4px 8px',
                        opacity: content.length > 0 ? '1' : '0',
                    }}
                    onClick={onConfirm}
                >Ok</Button>
            </div>
        );
    }

    function AntispamRule(props: { rule: AntispamRule }) {
        const [maxMsg, setMaxMsg] = useState(props.rule.max_msg);
        const [timeframe, setTimeframe] = useState(props.rule.timeframe);
        const [action, setAction] = useState(props.rule.action);
        const [message, setMessage] = useState(props.rule.message || '');
        const [channels, setChannels] = useState(props.rule.channels ?? []);
        const [channelsChanged, setChannelsChanged] = useState(false);

        const save = useCallback(async () => {
            await axios.patch(
                `${API_URL}/dash/server/${serverid}/automod/${props.rule.id}`,
                {
                    action: action != props.rule.action ? action : undefined,
                    channels: channelsChanged ? channels : undefined,
                    max_msg: maxMsg != props.rule.max_msg ? maxMsg : undefined,
                    message: message != props.rule.message ? message : undefined,
                    timeframe: timeframe != props.rule.timeframe ? timeframe : undefined,
                } as AntispamRule,
                { headers: await getAuthHeaders() }
            );

            await loadAutomodInfo(serverInfo);
        }, [maxMsg, timeframe, action, message, channels, channelsChanged]);

        const reset = useCallback(() => {
            setMaxMsg(props.rule.max_msg);
            setTimeframe(props.rule.timeframe);
            setAction(props.rule.action);
            setMessage(props.rule.message || '');
            setChannels(props.rule.channels ?? []);
            setChannelsChanged(false);
        }, []);

        const remove = useCallback(async () => {
            if (confirm(`Do you want to irreversably delete rule ${props.rule.id}?`)) {
                await axios.delete(`${API_URL}/dash/server/${serverid}/automod/${props.rule.id}`, { headers: await getAuthHeaders() });
                setAutomodSettings({ antispam: automodSettings!.antispam.filter(r => r.id != props.rule.id) });
            }
        }, []);

        const inputStyle: React.CSSProperties = {
            maxWidth: '100px',
            margin: '8px 8px 0px 8px',
        }

        const messagePlaceholders = {
            0: '',
            1: 'Message content...',
            2: '(Optional) Warn reason...',
            3: '',
            4: '',
        }

        return (
            <div>
                <span
                    style={{
                        color: 'var(--foreground)',
                    }}
                >
                    <div style={{ marginTop: '12px' }}>
                        If user sends more than
                        <InputBox style={inputStyle} value={maxMsg  || ''} placeholder={`${props.rule.max_msg}`} onChange={e => {
                            const val = e.currentTarget.value;
                            if (!isNaN(Number(val)) && val.length <= 4 && Number(val) >= 0) setMaxMsg(Number(val));
                        }} />
                        messages in
                        <InputBox style={inputStyle} value={timeframe || ''} placeholder={`${props.rule.timeframe}`} onChange={e => {
                            const val = e.currentTarget.value;
                            if (!isNaN(Number(val)) && val.length <= 4 && Number(val) >= 0) setTimeframe(Number(val));
                        }} />
                        seconds,
                        <ComboBox
                            style={{ ...inputStyle, maxWidth: '200px' }}
                            value={action}
                            onChange={ev => setAction(ev.currentTarget.value as any)}
                        >
                            <option value={0}>Delete message</option>
                            <option value={1}>Send a message</option>
                            <option value={2}>Warn user</option>
                            <option value={3}>Kick user</option>
                            <option value={4}>Ban user</option>
                        </ComboBox>
                        <InputBox
                            style={{
                                ...inputStyle,
                                maxWidth: 'min(400px, calc(100% - 20px))',
                                display: action >= 3 || action == 0 ? 'none' : 'unset' }}
                            value={message}
                            placeholder={messagePlaceholders[action] || ''}
                            onChange={ev => setMessage(ev.currentTarget.value)}
                        />
                        <a style={{ display: action >= 3 ? 'unset' : 'none'}}>
                            <br/>
                            "Kick" and "Ban" actions are currently placeholders, they do not have any functionality yet.
                        </a>

                        <H4 style={{ paddingTop: '16px' }}>
                            You can specify channels here that this rule will run in.
                            If left empty, it will run in all channels.
                        </H4>
                        <UserListTypeContainer>
                            <div style={{ display: 'flex', flexWrap: 'wrap' }}>
                                {
                                    channels.map(cid => {
                                        const channel: Channel = serverInfo.channels.find(c => c.id == cid && c.type == 'TEXT')
                                            || { id: cid, name: 'Unknown channel', nsfw: false, type: 'TEXT' };
                                        return (
                                            <div
                                                key={cid}
                                                style={{
                                                    display: 'block',
                                                    margin: '4px 6px',
                                                    padding: '4px',
                                                    backgroundColor: 'var(--tertiary-background)',
                                                    borderRadius: '5px',
                                                }}
                                            >
                                                <img
                                                    src={channel.icon ?? defaultChannelIcon}
                                                    style={{
                                                        width: '32px',
                                                        height: '32px',
                                                        objectFit: 'cover',
                                                        borderRadius: '10%',
                                                        verticalAlign: 'middle',
                                                        display: 'inline-block',
                                                    }}
                                                />
                                                <span
                                                    style={{
                                                        fontSize: '20px',
                                                        verticalAlign: 'middle',
                                                        marginLeft: '4px',
                                                    }}
                                                >{channel.name}</span>
                                                <RemoveButton onClick={() => {
                                                    setChannels(channels.filter(c => c != cid));
                                                    setChannelsChanged(true);
                                                }} />
                                            </div>
                                        )
                                    })
                                }
                                <ChannelListAddField onInput={channel => {
                                    if (!channels.includes(channel.id)) {
                                        setChannels([ ...channels, channel.id ]);
                                        setChannelsChanged(true);
                                    }
                                }} />
                            </div>
                        </UserListTypeContainer>
                    </div>
                </span>
                <div
                    style={{
                        paddingTop: '16px'
                    }}
                >
                    <Button style={{ float: 'left' }} onClick={save}>Save</Button>
                    <Button style={{ float: 'left', marginLeft: '8px' }} onClick={reset}>Reset</Button>
                    <Button style={{ float: 'left', marginLeft: '8px' }} onClick={remove}>Delete</Button>
                    <code
                        style={{
                            float: 'left',
                            color: 'var(--secondary-foreground)',
                            marginTop: '10px',
                            paddingLeft: '12px',
                        }}
                    >
                        {props.rule.id}
                    </code>
                    <div style={{ clear: 'both' }} />
                </div>
            </div>
        )
    }
}
export default ServerDashboard;
