import axios from "axios";
import { useState } from "react";
import { Input } from "@/components/ui/input";
import { Button } from "@/components/ui/button";
import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList } from "@/components/ui/command";
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
import { Label } from "@/components/ui/label";
import { Checkbox } from "@/components/ui/checkbox";
import { z } from "zod";
import { Trash2Icon } from "lucide-react";

interface Permission {
    id: string | undefined
    path: string
    allow: boolean | null
    groupId: string
    edit: boolean
    showEdit: boolean
    isNew: boolean
    permissionPaths: { path: string, description: string }[]
    adder: (id: string, path: string, allow: boolean | null) => void
    remover: (redemption: { id: string, path: string, allow: boolean | null }) => void,
    contains: (path: string) => boolean
}

const permissionPathSchema = z.string({
    required_error: "Permission path should be available.",
    invalid_type_error: "Permission path must be a string"
}).regex(/^[\w\-\.]{1,64}$/, "Permission path must contain only letters, numbers, dashes, periods.")
const permissionAllowSchema = z.boolean({
    required_error: "Permission should be allowed, revoked or inherited from parent.",
    invalid_type_error: "Something went wrong."
}).nullable()

const GroupPermission = ({
    id,
    path,
    allow,
    groupId,
    edit,
    showEdit,
    isNew,
    permissionPaths,
    adder,
    remover,
    contains
}: Permission) => {
    const [pathOpen, setPathOpen] = useState(false)
    const [isEditable, setIsEditable] = useState(edit)
    const [oldData, setOldData] = useState<{ path: string, allow: boolean | null } | undefined>(undefined)
    const [permission, setPermission] = useState<{ id: string | undefined, path: string, allow: boolean | null }>({ id, path, allow });
    const [error, setError] = useState<string | undefined>(undefined)

    function Save() {
        setError(undefined)
        if (!permission || !permission.path)
            return

        if (!permissionPaths.some(p => p.path == permission.path)) {
            setError('Permission does not exist.')
            return
        }

        const permissionPathValidation = permissionPathSchema.safeParse(permission.path)
        if (!permissionPathValidation.success) {
            setError(JSON.parse(permissionPathValidation.error['message'])[0].message)
            return
        }

        const permissionAllowValidation = permissionAllowSchema.safeParse(permission.allow)
        if (!permissionAllowValidation.success) {
            setError(JSON.parse(permissionAllowValidation.error['message'])[0].message)
            return
        }

        if (isNew) {
            if (contains(permission.path)) {
                setError("Permission already exists.")
                return;
            }

            axios.post("/api/settings/groups/permissions", {
                path: permission.path,
                allow: permission.allow,
                groupId: groupId
            }).then(d => {
                if (!d || !d.data)
                    return

                adder(d.data.id, permission.path, permission.allow)
                setPermission({ id: undefined, path: "", allow: true })
            })
        } else {
            if (!contains(permission.path)) {
                setError("Permission does not exists.")
                return;
            }

            axios.put("/api/settings/groups/permissions", {
                id: permission.id,
                path: permission.path,
                allow: permission.allow
            }).then(d => {
                setIsEditable(false)
            })
        }
    }

    function Cancel() {
        if (!oldData)
            return
        
        setError(undefined)
        setPermission({ ...oldData, id: permission.id })
        setIsEditable(false)
        setOldData(undefined)
    }

    function Delete() {
        axios.delete("/api/settings/groups/permissions?id=" + permission.id)
            .then(d => {
                remover(d.data)
            })
    }

    return (
        <div
            className="bg-green-400 p-2 border-2 border-green-500 rounded-lg grid grid-flow-row">
            <div
                className="pb-3 flex grow">
                {!isEditable &&
                    <Input
                        className="flex grow ml-1"
                        id="path"
                        value={permission.path}
                        readOnly />
                    || isEditable &&
                    <Popover
                        open={pathOpen}
                        onOpenChange={setPathOpen}>
                        <PopoverTrigger asChild>
                            <Button
                                variant="outline"
                                id="path"
                                role="combobox"
                                className="flex grow justify-between"
                            >{!permission.path ? "Select a permission" : permission.path}</Button>
                        </PopoverTrigger>
                        <PopoverContent>
                            <Command>
                                <CommandInput
                                    placeholder="Search..."
                                    inputMode="search"
                                    autoFocus={true} />
                                <CommandList>
                                    <CommandEmpty>No permission found.</CommandEmpty>
                                    <CommandGroup>
                                        {permissionPaths.map((p) => (
                                            <CommandItem
                                                value={p.path}
                                                key={p.path}
                                                onSelect={(value) => {
                                                    setPermission({ ...permission, path: permissionPaths.find(v => v.path.toLowerCase() == value.toLowerCase())?.path ?? value.toLowerCase() })
                                                    setPathOpen(false)
                                                }}>
                                                <div>
                                                    <div className="text-lg">
                                                        {p.path}
                                                    </div>
                                                    <div className="text-xs text-green-200">
                                                        {p.description}
                                                    </div>
                                                </div>

                                            </CommandItem>
                                        ))}
                                    </CommandGroup>
                                </CommandList>
                            </Command>
                        </PopoverContent>
                    </Popover>
                }
            </div>
            <div
                className="grid grid-cols-2 gap-1">
                <Label>
                    Inherit from parent
                </Label>
                <Checkbox
                    checked={permission.allow === null}
                    onCheckedChange={(e) => {
                        if (permission.allow === null)
                            setPermission({ ...permission, allow: false })
                        else
                            setPermission({ ...permission, allow: null })
                    }}
                    disabled={!isEditable} />
                <Label
                    htmlFor="inherit">
                    Allow
                </Label>
                <Checkbox
                    id="inherit"
                    checked={permission.allow === true}
                    onCheckedChange={(e) => {
                        setPermission({ ...permission, allow: !permission.allow })
                    }}
                    disabled={!isEditable || permission === undefined} />
            </div>
            {error &&
                <p className="w-[380px] text-red-600 text-wrap text-sm">
                    {error}
                </p>
            }
            <div>
                {isEditable &&
                    <Button
                        className="m-3"
                        onClick={() => Save()}>
                        {isNew ? "Add" : "Save"}
                    </Button>
                }
                {isEditable && !isNew &&
                    <Button
                        className="m-3"
                        onClick={() => Cancel()}>
                        Cancel
                    </Button>
                }
                {showEdit && !isEditable &&
                    <Button
                        className="m-3"
                        onClick={() => {
                            setOldData({ ...permission })
                            setIsEditable(true)
                        }}>
                        Edit
                    </Button>
                }
                {!isEditable &&
                    <Button
                        className="m-3 bg-red-500 hover:bg-red-600 align-bottom"
                        onClick={() => Delete()}>
                        <Trash2Icon />
                    </Button>
                }
            </div>
        </div>
    );
}

export default GroupPermission;