import axios from "axios";
import { useState } from "react";
import { Input } from "@/components/ui/input";
import { Button } from "@/components/ui/button";
import { Label } from "../ui/label";
import { Maximize2, Minimize2, Trash2Icon } from "lucide-react";
import GroupPermission from "./group-permission";
import { z } from "zod";
import UserList from "./user-list-group";

interface Group {
    id: string | undefined
    name: string
    priority: number
    permissionsLoaded: { id: string, path: string, allow: boolean | null }[]
    edit: boolean
    showEdit: boolean
    isNewGroup: boolean
    permissionPaths: { path: string, description: string }[]
    specialGroups: string[]
    adder: (id: string, name: string, priority: number) => void
    remover: (group: { id: string, name: string, priority: number }) => void
}

const GroupElement = ({
    id,
    name,
    priority,
    permissionsLoaded,
    edit,
    showEdit,
    isNewGroup,
    permissionPaths,
    specialGroups,
    adder,
    remover
}: Group) => {
    const [isEditable, setIsEditable] = useState(edit)
    const [isNew, setIsNew] = useState(isNewGroup)
    const [isMinimized, setIsMinimized] = useState(true)
    const [oldData, setOldData] = useState<{ name: string, priority: number } | undefined>(undefined)
    const [group, setGroup] = useState<{ id: string | undefined, name: string, priority: number }>({ id, name, priority })
    const [permissions, setPermissions] = useState<{ id: string, path: string, allow: boolean | null }[]>(permissionsLoaded);
    const isSpecial = (isEditable || oldData === undefined) && !!group && specialGroups.includes(group?.name)
    const [error, setError] = useState<string | undefined>(undefined)


    function addPermission(id: string, path: string, allow: boolean | null) {
        setPermissions([...permissions, { id, path, allow }])
    }

    function removePermission(permission: { id: string, path: string, allow: boolean | null }) {
        setPermissions(permissions.filter(p => p.id != permission.id))
    }

    const nameSchema = z.string({
        required_error: "Name is required.",
        invalid_type_error: "Name must be a string"
    }).regex(/^[\w\-\s]{1,20}$/, "Name must contain only letters, numbers, dashes, and underscores.")
    const prioritySchema = z.string().regex(/^-?\d{1,5}$/, "Priority must be a valid number.")

    function Save() {
        setError(undefined)
        if (!isNew && !id)
            return

        const nameValidation = nameSchema.safeParse(group.name)
        if (!nameValidation.success) {
            setError(JSON.parse(nameValidation.error['message'])[0].message)
            return
        }

        const priorityValidation = prioritySchema.safeParse(group.priority.toString())
        if (!priorityValidation.success) {
            setError(JSON.parse(priorityValidation.error['message'])[0].message)
            return
        }

        if (isNew || group.id?.startsWith('$')) {
            axios.post("/api/settings/groups", {
                name: group.name,
                priority: group.priority
            }).then(d => {
                if (!d) {
                    setError("Something went wrong.")
                    return
                }
                console.log("DATA", d.data)

                if (specialGroups.includes(group.name)) {
                    setIsNew(false)
                    setIsEditable(false)
                    setGroup({ id: d.data.id, name: d.data.name, priority: d.data.priority })
                } else {
                    adder(d.data.id, group.name.toLowerCase(), group.priority)
                    setGroup({ id: undefined, name: "", priority: 0 })
                }
            }).catch(() => {
                setError("Potential group name duplicate.")
            })
        } else {
            axios.put("/api/settings/groups", {
                id: group.id,
                name: group.name,
                priority: group.priority
            }).then(d => {
                console.log("DATA", d.data)
                setIsEditable(false)
            }).catch(() => {
                setError("Potential group name duplicate.")
            })
        }
    }

    function Cancel() {
        setError(undefined)
        if (!oldData)
            return

        setGroup({ ...oldData, id: group.id })
        setIsEditable(false)
        setOldData(undefined)
    }

    function Delete() {
        axios.delete("/api/settings/groups?id=" + group.id)
            .then(d => {
                if (specialGroups.includes(group.name)) {
                    setPermissions([])
                    setIsMinimized(true)
                    setOldData(undefined)
                    setIsNew(true)
                    setIsEditable(true)
                } else
                    remover(d.data)
            })
    }

    return (
        <div
            className="bg-green-300 p-5 border-2 border-green-400 rounded-lg">
            <div
                className="pb-4">

                <div
                    className="justify-between">
                    <Label
                        className="mr-2 text-black"
                        htmlFor="path">
                        Group Name
                    </Label>
                    {isSpecial &&
                        <div className="bg-white text-muted text-xs p-1 rounded m-1 inline-block">
                            auto-generated
                        </div>
                    }
                    <Input
                        value={group.name}
                        id="path"
                        onChange={e => setGroup({ ...group, name: e.target.value })}
                        readOnly={isSpecial || !isEditable} />
                </div>
                <div
                    className="justify-between">
                    <Label
                        className="mr-2 text-black"
                        htmlFor="priority">
                        TTS Priority
                    </Label>
                    <Input
                        name="priority"
                        value={group.priority}
                        onChange={e => setGroup(d => {
                            let temp = { ...group }
                            const v = parseInt(e.target.value)
                            if (e.target.value.length == 0) {
                                temp.priority = 0
                            } else if (!Number.isNaN(v) && Number.isSafeInteger(v)) {
                                temp.priority = v
                            } else if (Number.isNaN(v)) {
                                temp.priority = 0
                            }
                            return temp
                        })}
                        readOnly={!isEditable} />
                </div>
            </div>
            <p className="w-[380px] text-red-500 text-wrap text-sm">
                {error}
            </p>
            <div>
                {isEditable &&
                    <Button
                        className="ml-1 mr-1 align-middle"
                        onClick={() => Save()}>
                        {isNew ? "Add" : "Save"}
                    </Button>
                }
                {isEditable && !isNew &&
                    <Button
                        className="ml-1 mr-1 align-middle"
                        onClick={() => Cancel()}>
                        Cancel
                    </Button>
                }
                {showEdit && !isEditable &&
                    <Button
                        className="ml-1 mr-1 align-middle"
                        onClick={() => {
                            setOldData({ ...group })
                            setIsEditable(true)
                        }}>
                        Edit
                    </Button>
                }
                {!isEditable && !isNew &&
                    <Button
                        className="ml-1 mr-1 align-middle bg-red-500 hover:bg-red-600"
                        onClick={() => Delete()}>
                        <Trash2Icon />
                    </Button>
                }
                {!isNew && !group?.id?.startsWith('$') &&
                    <Button
                        className="ml-1 mr-1 align-middle"
                        onClick={e => setIsMinimized(!isMinimized)}>
                        {isMinimized ? <Maximize2 /> : <Minimize2 />}
                    </Button>
                }
                {!isNew && !isSpecial &&
                    <UserList
                        groupId={group.id!}
                        groupName={group.name} />
                }
            </div>

            {!isNew && !isMinimized &&
                <div>
                    {permissions.map(permission =>
                        <div
                            className="m-3 mb-0"
                            key={permission.id}>
                            <GroupPermission
                                id={permission.id}
                                path={permission.path}
                                allow={permission.allow}
                                groupId={group.id!}
                                edit={false}
                                showEdit={true}
                                isNew={false}
                                permissionPaths={permissionPaths}
                                adder={addPermission}
                                remover={removePermission} />
                        </div>
                    )}
                    <div
                        className="m-3 mb-0">
                        <GroupPermission
                            id={undefined}
                            path={""}
                            allow={true}
                            groupId={group.id!}
                            edit={true}
                            showEdit={false}
                            isNew={true}
                            permissionPaths={permissionPaths}
                            adder={addPermission}
                            remover={removePermission} />
                    </div>
                </div>
            }
        </div>
    );
}

export default GroupElement;