"use client";
import React, { useState, useMemo, useRef, useCallback } from "react";
import { PlusIcon } from '@radix-ui/react-icons';
import { useFieldArray } from "react-hook-form";
import { useFormGroupName } from "react-compose-form";
import { Select, SelectTrigger, SelectValue, SelectContent, SelectItem } from "@/components/ui/field/select";
import { InputControl } from "@/components/form/control/input.control";
import { FormLabel } from "@/components/form/form-label";
import { FormMessage } from "@/components/form/form-message";
import { Button } from "@/components/ui/button";
import { TagModalEditor, TagModalEditorRef } from "@/components/dashboard/tag/tag-modal-editor";
import { api } from "@/lib/trpc/client";
import { AppRouterOutput } from "@/lib/trpc/router";

type Tag = NonNullable<AppRouterOutput["tags"]["get"]>;

type TagInfo = {
    name: string;
    slug: string;
};

type TagData = {
    tagId: string;
    tag?: TagInfo;
};

type TagCollectionProps = {
    label?: string;
    name: string;
    placeholder?: string;
};

export const TagCollection: React.FC<TagCollectionProps> = (props) => {
    const {
        label,
        name,
        placeholder
    } = props;

    const fullName = useFormGroupName(name);
    const [search, setSearch] = useState<string>();

    const editorRef = useRef<TagModalEditorRef>(null);

    const {
        fields,
        append,
        replace
    } = useFieldArray<{
        [key: typeof fullName]: TagData[];
    }>({
        name: fullName
    });

    const ids = useMemo(() => {
        return fields.map(r => r.tagId);
    }, [fields]);

    const {
        data: { pages = [] } = {},
        isFetching,
        fetchNextPage,
        hasNextPage
    } = api.tags.paginate.useInfiniteQuery({
        search,
        limit: 15
    }, {
        getNextPageParam: (lastPage) => lastPage.nextCursor
    });

    const getTag = useCallback((tagId: string): TagInfo | undefined => {
        const field = fields.find(f => f.tagId === tagId);

        if(field && field.tag) {
            return field.tag;
        }

        for(const page of pages) {
            for(const tag of page.items) {
                if(tag.id === tagId) {
                    return tag;
                }
            }
        }

        return undefined;
    }, [fields, pages]);

    const handleCreateTag = useCallback((tag: Tag) => {
        append({
            tagId: tag.id,
            tag: {
                name: tag.name,
                slug: tag.slug
            }
        });
    }, [append]);

    const handleChange = useCallback((ids: string[]) => {
        const selectedTags = ids.map((id) => {
            return {
                tagId: id,
                tag: getTag(id)
            };
        });

        replace(selectedTags);
    }, [replace, getTag]);

    const handleScroll = useCallback(() => {
        if(!hasNextPage) {
            return;
        }

        return fetchNextPage();
    }, [hasNextPage, fetchNextPage]);

    return (
        <div className="grid gap-2">
            {label && (
                <FormLabel className="flex justify-between" name={fullName}>
                    {label}

                    <Button
                      type="button"
                      variant="ghost"
                      title="Create new tag"
                      size="sm"
                      onClick={() => editorRef.current?.open()}>
                        <PlusIcon />
                    </Button>
                </FormLabel>
            )}

            <Select
              multiple
              name={fullName}
              value={ids}
              onOpenChange={(open) => !open && setSearch(undefined)}
              onValueChange={handleChange}>
                <SelectTrigger className="w-full">
                    <SelectValue clickToRemove placeholder={placeholder} />
                </SelectTrigger>

                <SelectContent
                  searchable
                  loading={isFetching}
                  search={search}
                  onSearch={setSearch}
                  onScrollReachBottom={handleScroll}>
                    {fields.map((field) => {
                        return (
                            <SelectItem key={field.tagId} value={field.tagId}>
                                {field.tag?.name}
                            </SelectItem>
                        );
                    })}

                    {pages.map((page) => {
                        return page.items.filter((tag) => !ids.includes(tag.id)).map((tag) => {
                            return (
                                <SelectItem key={tag.id} value={tag.id}>{tag.name}</SelectItem>
                            );
                        });
                    })}
                </SelectContent>
            </Select>

            {fields.map((field, index) => {
                return (
                    <React.Fragment key={field.id}>
                        <InputControl
                          type="hidden"
                          name={`${fullName}.${index}.tagId`} />

                        <InputControl
                          type="hidden"
                          name={`${fullName}.${index}.tag.name`} />
                    </React.Fragment>
                );
            })}

            <FormMessage absolute name={fullName} />

            <TagModalEditor
              ref={editorRef}
              onCreate={handleCreateTag} />
        </div>
    );
};
