import React, { useState, useCallback, useEffect, useMemo } from "react";
import { useTranslations } from "next-intl";
import { PlusIcon } from "lucide-react";
import { toast } from "sonner";
import { FormSubmit } from "@/components/form/form-submit";
import {
    Dialog,
    DialogClose,
    DialogContent,
    DialogDescription,
    DialogFooter,
    DialogHeader,
    DialogTitle
} from "@/components/ui/dialog";
import { Button } from "@/components/ui/button";
import { ResourcePickerItem } from "@/components/ui/resource-picker/resource-picker-item";
import { ResourcePickerList } from "@/components/ui/resource-picker/resource-picker-list";
import { DatasetFilters } from "@/components/ui/dataset";
import { ProfilePreview } from "@/components/dashboard/profile/profile-preview";
import { SwitchControl } from "@/components/form/control/switch.control";
import { Profile } from "@/components/ui/profile-picker/profile-picker.context";
import { ProfileForm } from "@/components/dashboard/profile/forms/profile.form";
import { api } from "@/lib/trpc/client";

export type ProfilePickerProps = {
    open?: boolean;
    editId?: string;
    autosubmit?: boolean;
    personal?: boolean;
    multiple?: boolean;
    selected?: string[];
    onSelect?: (ids: string[]) => void;
    onCreate?: (profile: Profile) => void;
    onOpenChange?: (open: boolean) => void;
};

export type ProfilePickerMode = "select" | "create" | "edit";

export const ProfilePicker: React.FC<ProfilePickerProps> = (props) => {
    const {
        open,
        editId,
        autosubmit,
        personal,
        multiple,
        selected = [],
        onSelect,
        onCreate,
        onOpenChange
    } = props;

    const [isOpen, setOpen] = useState(open),
          [selectedIds, setSelectedIds] = useState<string[]>(selected),
          [filters, setFilters] = useState<{ search?: string; isPersonal?: boolean }>({ isPersonal: personal }),
          [mode, setMode] = useState<ProfilePickerMode>("select");

    const utils = api.useUtils();
    const t = useTranslations("dashboard.profile");

    const {
        data: {
            pages = []
        } = {},
        isFetching,
        fetchNextPage,
        hasNextPage
    } = api.profile.paginate.useInfiniteQuery({
        search: filters.search,
        isPersonal: filters.isPersonal,
        limit: 12,
        orderBy: "createdAt",
        orderDir: "desc"
    }, {
        getNextPageParam: (lastPage) => lastPage.nextCursor
    });

    const {
        data: editProfile,
        isLoading: isEditLoading
    } = api.profile.get.useQuery({
        id: editId!
    }, {
        enabled: !!editId && mode === "edit"
    });

    const createMutation = api.profile.create.useMutation({
        async onSuccess(profile) {
            const nextIds = multiple ? [...selectedIds, profile.id] : [profile.id];

            setSelectedIds(nextIds);
            setMode("select");

            if(onCreate) {
                onCreate(profile as Profile);
            }

            await utils.profile.paginate.invalidate();

            if(autosubmit && !multiple) {
                handleSelect(nextIds);
            }
        }
    });

    const updateMutation = api.profile.update.useMutation({
        async onSuccess(profile) {
            const nextIds = multiple ? [...selectedIds, profile.id] : [profile.id];

            setSelectedIds(nextIds);
            setMode("select");

            await utils.profile.paginate.invalidate();
            await utils.profile.get.invalidate({ id: profile.id });

            if(autosubmit && !multiple) {
                handleSelect(nextIds);
            }
        },
        onError(error) {
            toast.error(error.message || "Some");
        }
    });

    const handleSelect = useCallback((ids: string[] = selectedIds) => {
        if(onSelect) {
            onSelect(ids);
        }

        setOpen(false);
    }, [onSelect, selectedIds]);

    const handleSave = useCallback(() => {
        handleSelect(selectedIds);
    }, [selectedIds, handleSelect]);

    const handleOpenChange = useCallback((open: boolean) => {
        setOpen(open);

        if(onOpenChange) {
            onOpenChange(open);
        }
    }, [onOpenChange]);

    const handleSelectChange = useCallback((ids: string[]) => {
        setSelectedIds(ids);

        if(autosubmit && !multiple && ids.length > 0) {
            handleSelect(ids);
        }
    }, [autosubmit, multiple, handleSelect]);

    useEffect(() => {
        setOpen(open);

        if(!isOpen && open) {
            setMode(editId ? "edit" : "select");
            setSelectedIds(selected);
            setFilters({
                isPersonal: personal
            });
        }
    }, [open, selected, isOpen, editId, personal]);

    const items = useMemo(() => pages.flatMap(page => page.items), [pages]);

    const getTitle = () => {
        if(mode === "create") return t("editor.create.title");
        if(mode === "edit") return t("editor.update.title");

        return t("picker.title");
    };

    const getDescription = () => {
        if(mode === "create") return t("editor.create.description");
        if(mode === "edit") return t("editor.update.description");

        return t("picker.description");
    };

    return (
        <Dialog open={isOpen} onOpenChange={handleOpenChange}>
            <DialogContent className="flex flex-col min-h-1 max-h-[90vh]">
                <DialogHeader>
                    <DialogTitle>{getTitle()}</DialogTitle>

                    <DialogDescription>
                        {getDescription()}
                    </DialogDescription>
                </DialogHeader>

                {mode === "create" && (
                    <ProfileForm
                      id="profile-create-form"
                      className="contents"
                      onSubmit={async (data) => {
                        await createMutation.mutateAsync({ data });
                      }}>
                        <DialogFooter className="pt-4 border-t">
                            <DialogClose asChild>
                                <Button variant="outline">{t("actions.cancel")}</Button>
                            </DialogClose>

                            <FormSubmit form="profile-create-form">
                                {t("actions.create")}
                            </FormSubmit>
                        </DialogFooter>
                    </ProfileForm>
                )}

                {mode === "edit" && !isEditLoading && (
                    <ProfileForm
                      id="profile-edit-form"
                      className="contents"
                      values={editProfile ? {
                        name: editProfile.name,
                        slug: editProfile.slug || "",
                        jobInfo: editProfile.jobInfo,
                        avatarId: editProfile.avatarId,
                        userId: editProfile.userId,
                        isMain: editProfile.isMain
                      } : undefined}
                      onSubmit={async (data) => {
                        await updateMutation.mutateAsync({
                            id: editId!,
                            data
                        });
                      }}>
                        <DialogFooter className="pt-4 border-t">
                            <DialogClose asChild>
                                <Button variant="outline">{t("actions.cancel")}</Button>
                            </DialogClose>

                            <FormSubmit form="profile-edit-form">
                                {t("actions.save")}
                            </FormSubmit>
                        </DialogFooter>
                    </ProfileForm>
                )}

                {mode === "select" && (
                    <React.Fragment>
                        <div className="flex justify-between items-center gap-4">
                            <DatasetFilters
                              search
                              filters={filters}
                              onChange={setFilters}>
                                <SwitchControl
                                  label={t("filters.isPersonal.label")}
                                  name="isPersonal" />
                            </DatasetFilters>

                            <Button
                              type="button"
                              variant="secondary"
                              size="icon"
                              title={t("actions.createNew")}
                              onClick={() => setMode("create")}>
                                <PlusIcon />
                            </Button>
                        </div>

                        <div className="flex-1 overflow-y-auto min-h-0 py-4">
                            <ResourcePickerList
                              multiple={multiple}
                              selected={selectedIds}
                              isFetching={isFetching}
                              hasNextPage={hasNextPage}
                              fetchNextPage={fetchNextPage}
                              onChange={handleSelectChange}>
                                {items.map((profile) => (
                                    <ResourcePickerItem key={profile.id} id={profile.id}>
                                        <ProfilePreview
                                          size={50}
                                          avatar={profile.avatar}
                                          name={profile.name}
                                          jobInfo={profile.jobInfo} />
                                    </ResourcePickerItem>
                                ))}
                            </ResourcePickerList>
                        </div>
                    </React.Fragment>
                )}

                {mode === "select" && (
                    <DialogFooter className="pt-4 border-t">
                        <DialogClose asChild>
                            <Button variant="outline">{t("actions.cancel")}</Button>
                        </DialogClose>

                        <Button type="button" onClick={handleSave}>
                            {t("actions.confirm")}
                        </Button>
                    </DialogFooter>
                )}
            </DialogContent>
        </Dialog>
    );
};
