import React, { useState, useCallback, useEffect } from "react";
import { useTranslations } from "next-intl";
import { FormProvider } from "react-hook-form";
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 { SwitchControl } from "@/components/form/control/switch.control";
import { MediaCreateManyForm, useMediaCreateManyForm, MediaCreateManyFormValues } from "@/components/dashboard/media/media-create-many-form";
import { MediaPreview } from "@/components/dashboard/media/media-preview";
import { objectToFormdata } from "@/lib/utils/object-to-formdata";
import { api } from "@/lib/trpc/client";
import { MediaScope } from "@/server/modules/media/types/media-scope.enum";
import { Media } from "@/components/ui/media-picker/media-picker.context";

export type MediaPickerProps = {
    open?: boolean;
    autosubmit?: boolean;
    multiple?: boolean;
    withAttachments?: boolean;
    defaultAttached?: boolean;
    attached?: string[];
    selected?: string[];
    scope?: MediaScope;
    acceptedFileTypes?: string[];
    mimeType?: string | string[];
    onSelect?: (ids: string[]) => void;
    onCreate?: (medias: Media[]) => void;
    onOpenChange?: (open: boolean) => void;
};

export const MediaPicker: React.FC<MediaPickerProps> = (props) => {
    const {
        open,
        multiple,
        autosubmit,
        withAttachments,
        defaultAttached,
        attached,
        selected,
        scope = MediaScope.POST,
        acceptedFileTypes,
        mimeType,
        onSelect,
        onCreate,
        onOpenChange
    } = props;

    const [isOpen, setOpen] = useState(open),
          [selectedIds, setSelectedIds] = useState<string[]>(selected || []),
          [params, setParams] = useState<{ search?: string; onlyAttached?: boolean }>({
              onlyAttached: withAttachments && defaultAttached && attached && attached.length > 0
          });

    const utils = api.useUtils();
    const form = useMediaCreateManyForm();

    const t = useTranslations("dashboard.media");

    const medias = form.watch("data") || [];

    const {
        data: { pages = [] } = {},
        isFetching,
        fetchNextPage,
        hasNextPage
    } = api.media.paginate.useInfiniteQuery({
        mimeType,
        scope,
        ids: withAttachments && params.onlyAttached && attached && attached.length > 0 ? attached : undefined,
        limit: 12,
        search: params.search || undefined,
        orderBy: "createdAt",
        orderDir: "desc"
    }, {
        getNextPageParam: (lastPage) => lastPage.nextCursor
    });

    const createManyMutation = api.media.createMany.useMutation({
        async onSuccess(medias) {
            setSelectedIds((ids) => {
                const selected = [...ids, ...medias.map((m) => m.id)];

                if(!multiple && selected.length > 0) {
                    return [selected.pop() as string];
                }

                return selected;
            });

            form.reset();

            if(onCreate) {
                onCreate(medias);
            }

            await utils.media.paginate.invalidate({
                limit: 12,
                orderBy: "createdAt",
                orderDir: "desc"
            });
        }
    });

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

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

    const handleCreateMedia = useCallback(async (data: MediaCreateManyFormValues) => {
        await createManyMutation.mutateAsync(objectToFormdata(data));
    }, [createManyMutation]);

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

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

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

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

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

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

        if(!isOpen && open) {
            setSelectedIds(selected || []);

            setParams({
                search: undefined,
                onlyAttached: !!(defaultAttached && attached && attached.length > 0)
            });
        }
    }, [isOpen, selected, attached, open, defaultAttached]);

    return (
        <Dialog open={isOpen} onOpenChange={handleOpenChange}>
            <DialogContent className="max-h-screen overflow-y-auto overscroll-x-auto">
                <FormProvider {...form}>
                    <DialogHeader>
                        {medias.length === 0 && (
                            <React.Fragment>
                                <DialogTitle>{t("picker.title")}</DialogTitle>
                                <DialogDescription>{t("picker.description")}</DialogDescription>
                            </React.Fragment>
                        )}

                        {medias.length > 0 && (
                            <DialogTitle>{t("actions.upload")}</DialogTitle>
                        )}
                    </DialogHeader>

                    <div className="flex flex-col gap-4">
                        <MediaCreateManyForm
                          id="media-picker-form"
                          control={form}
                          scope={scope}
                          acceptedFileTypes={acceptedFileTypes}
                          onSubmit={handleCreateMedia} />

                        <div className={medias.length > 0 ? "hidden" : "contents"}>
                            <DatasetFilters
                              search
                              filters={params}
                              onChange={setParams}>
                                {withAttachments && attached && attached.length > 0 && (
                                    <SwitchControl
                                      label={t("picker.attached")}
                                      name="onlyAttached" />
                                )}
                            </DatasetFilters>

                            <ResourcePickerList
                              className="max-h-100"
                              multiple={multiple}
                              selected={selectedIds}
                              isFetching={isFetching}
                              hasNextPage={hasNextPage}
                              fetchNextPage={fetchNextPage}
                              onChange={handleSelectionChange}>
                                {pages.map(({ items }, index) => {
                                    return (
                                        <div key={index} className="contents">
                                            {items.map((media) => {
                                                return (
                                                    <ResourcePickerItem key={media.id} id={media.id}>
                                                        <MediaPreview
                                                            size="100%"
                                                            originalName={media.originalName}
                                                            mimeType={media.mimeType}
                                                            alt={media.alt || ""}
                                                            author={media.author || ""}
                                                            caption={media.caption || ""}
                                                            url={media.url}
                                                        />
                                                    </ResourcePickerItem>
                                                );
                                            })}
                                        </div>
                                    );
                                })}
                            </ResourcePickerList>
                        </div>
                    </div>

                    <DialogFooter className="pt-4 border-t">
                        <DialogClose type="button">{t("actions.cancel")}</DialogClose>

                        {medias.length === 0 && (
                            <Button type="button" onClick={handleSave}>
                                {t("actions.save")}
                            </Button>
                        )}

                        {medias.length > 0 && (
                            <FormSubmit form="media-picker-form">
                                {t("actions.create")}
                            </FormSubmit>
                        )}
                    </DialogFooter>
                </FormProvider>
            </DialogContent>
        </Dialog>
    );
};
