import { definePluginSettings } from "@api/Settings";
import { Devs } from "@utils/constants";
import definePlugin, { OptionType } from "@utils/types";
import { findByProps, findByPropsLazy, findComponentByCode } from "@webpack";
import { FluxDispatcher, Forms, Select, Slider, Text, useEffect } from "@webpack/common";
import { useState } from "@webpack/common";
import { identity } from "@utils/misc";
import { boolean } from "ts-pattern/dist/patterns";
import { Settings } from "Vencord";
import { Link } from "@components/Link";

const audioConfigModule = findByPropsLazy("getOutputVolume");

function OutputVolumeComponent() {
    const [outputVolume, setOutputVolume] = useState(audioConfigModule.getOutputVolume());

    useEffect(() => {
        const listener = () => setOutputVolume(audioConfigModule.getOutputVolume());
        FluxDispatcher.subscribe("AUDIO_SET_OUTPUT_VOLUME", listener);
    });

    return (
        <>
            {Settings.plugins.VCPanelSettings.showOutputVolumeHeader && <Forms.FormTitle>Output volume - {Math.floor(outputVolume)}%</Forms.FormTitle>}
            <Slider maxValue={200} minValue={0} initialValue={outputVolume} hideBubble={Settings.plugins.VCPanelSettings.showOutputVolumeHeader} onValueChange={(volume) => {
                FluxDispatcher.dispatch({
                    type: "AUDIO_SET_OUTPUT_VOLUME",
                    volume
                });
            }} />
        </>
    );
}

function InputVolumeComponent() {
    const [inputVolume, setInputVolume] = useState(audioConfigModule.getInputVolume());

    useEffect(() => {
        const listener = () => setInputVolume(audioConfigModule.getInputVolume());
        FluxDispatcher.subscribe("AUDIO_SET_INPUT_VOLUME", listener);
    });

    return (
        <>
            {Settings.plugins.VCPanelSettings.showInputVolumeHeader && <Forms.FormTitle>Input volume - {Math.floor(inputVolume)}%</Forms.FormTitle>}
            <Slider maxValue={100} minValue={0} initialValue={inputVolume} onValueChange={(volume) => {
                FluxDispatcher.dispatch({
                    type: "AUDIO_SET_INPUT_VOLUME",
                    volume
                });
            }} />
        </>
    );
}

function OutputDeviceComponent() {
    const [outputDevice, setOutputDevice] = useState(audioConfigModule.getOutputDeviceId());

    useEffect(() => {
        const listener = () => setOutputDevice(audioConfigModule.getOutputDeviceId());
        FluxDispatcher.subscribe("AUDIO_SET_OUTPUT_DEVICE", listener);
    });

    return (
        <>
            {Settings.plugins.VCPanelSettings.showOutputDeviceHeader && <Forms.FormTitle>Output device</Forms.FormTitle>}
            <Select options={Object.values(audioConfigModule.getOutputDevices()).map((device: any /*i am NOT typing this*/) => {
                return { value: device.id, label: Settings.plugins.VCPanelSettings.showOutputDeviceHeader ? device.name : `🔊 ${device.name}` };
            })}
                serialize={identity}
                isSelected={(value) => value === outputDevice}
                select={(id) => {
                    FluxDispatcher.dispatch({
                        type: "AUDIO_SET_OUTPUT_DEVICE",
                        id
                    });
                }}>

            </Select>
        </>
    );
}

function InputDeviceComponent() {
    const [inputDevice, setInputDevice] = useState(audioConfigModule.getInputDeviceId());

    useEffect(() => {
        const listener = () => setInputDevice(audioConfigModule.getInputDeviceId());
        FluxDispatcher.subscribe("AUDIO_SET_INPUT_DEVICE", listener);
    });

    return (
        <div style={{ marginTop: "10px" }}>
            {Settings.plugins.VCPanelSettings.showInputDeviceHeader && <Forms.FormTitle>Input device</Forms.FormTitle>}
            <Select options={Object.values(audioConfigModule.getInputDevices()).map((device: any /*i am NOT typing this*/) => {
                return { value: device.id, label: Settings.plugins.VCPanelSettings.showInputDeviceHeader ? device.name : `🎤 ${device.name}` };
            })}
                serialize={identity}
                isSelected={(value) => value === inputDevice}
                select={(id) => {
                    FluxDispatcher.dispatch({
                        type: "AUDIO_SET_INPUT_DEVICE",
                        id
                    });
                }}>

            </Select>
        </div>
    );
}

function VoiceSettings() {
    return <div style={{ marginTop: "20px" }}>
        {Settings.plugins.VCPanelSettings.outputVolume && <OutputVolumeComponent />}
        {Settings.plugins.VCPanelSettings.inputVolume && <InputVolumeComponent />}
        {Settings.plugins.VCPanelSettings.outputDevice && <OutputDeviceComponent />}
        {Settings.plugins.VCPanelSettings.inputDevice && <InputDeviceComponent />}
    </div>;
}

export default definePlugin({
    name: "VCPanelSettings",
    description: "Control voice settings right from the voice panel",
    authors: [Devs.nin0dev],
    settings: definePluginSettings({
        showOutputVolumeHeader: {
            type: OptionType.BOOLEAN,
            default: true,
            description: "Show header above output volume slider"
        },
        outputVolume: {
            type: OptionType.BOOLEAN,
            default: true,
            description: "Show an output volume slider"
        },
        showInputVolumeHeader: {
            type: OptionType.BOOLEAN,
            default: true,
            description: "Show header above input volume slider"
        },
        inputVolume: {
            type: OptionType.BOOLEAN,
            default: true,
            description: "Show an input volume slider"
        },
        showOutputDeviceHeader: {
            type: OptionType.BOOLEAN,
            default: false,
            description: "Show header above output device slider"
        },
        outputDevice: {
            type: OptionType.BOOLEAN,
            default: true,
            description: "Show an output device selector"
        },
        showInputDeviceHeader: {
            type: OptionType.BOOLEAN,
            default: false,
            description: "Show header above input device slider"
        },
        inputDevice: {
            type: OptionType.BOOLEAN,
            default: true,
            description: "Show an input device selector"
        }
    }),
    renderVoiceSettings() { return <VoiceSettings />; },
    patches: [
        {
            find: "this.renderChannelButtons()",
            replacement: {
                match: /this.renderChannelButtons\(\)/,
                replace: "this.renderChannelButtons(), $self.renderVoiceSettings()"
            }
        }
    ]
});
