"use client";

import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
import { Badge } from "@/components/ui/badge";
import { Input } from "@/components/ui/input";
import { useQuery } from "@/hooks/use-swr";
import { cn } from "@/lib/utils";
import apiClient from "@/lib/api/client";
import { User } from "@/types/user";
import { ChevronDown, Search, X } from "lucide-react";
import { useEffect, useMemo, useRef, useState } from "react";

interface ClientMultiSelectorProps {
  value: number[];
  onChange: (ids: number[]) => void;
  onSelectedUsersChange?: (users: User[]) => void;
  label?: string;
  hint?: string;
  roleId?: number;
  showHeader?: boolean;
}

type UsersListResponse = {
  data: User[];
  meta?: {
    current_page: number;
    last_page: number;
  };
};

const USERS_PAGE_SIZE = 20;

export function ClientMultiSelector({
  value = [],
  onChange,
  onSelectedUsersChange,
  label = "Project Access Users",
  hint = "(You can select multiple options)",
  roleId,
  showHeader = true,
}: ClientMultiSelectorProps) {
  const [isOpen, setIsOpen] = useState(!showHeader);
  const [searchQuery, setSearchQuery] = useState("");
  const [debouncedSearch, setDebouncedSearch] = useState("");
  const [page, setPage] = useState(1);
  const [loadedUsers, setLoadedUsers] = useState<User[]>([]);
  const [hasMore, setHasMore] = useState(true);
  const [userCache, setUserCache] = useState<Map<number, User>>(new Map());
  const loadingMoreRef = useRef(false);

  useEffect(() => {
    const timeoutId = setTimeout(() => {
      setDebouncedSearch(searchQuery.trim());
    }, 300);
    return () => clearTimeout(timeoutId);
  }, [searchQuery]);

  useEffect(() => {
    const timeoutId = setTimeout(() => {
      setPage(1);
      setLoadedUsers([]);
      setHasMore(true);
      loadingMoreRef.current = false;
    }, 0);
    return () => clearTimeout(timeoutId);
  }, [debouncedSearch, roleId]);

  const queryParams = useMemo(() => {
    const params: Record<string, string | number> = {
      page,
      per_page: USERS_PAGE_SIZE,
    };
    if (roleId) {
      params.role_id = roleId;
    }
    if (debouncedSearch) {
      params.search = debouncedSearch;
    }
    return params;
  }, [debouncedSearch, page, roleId]);

  const queryOptions = useMemo(
    () => ({
      onSuccess: (response: UsersListResponse) => {
        const responseUsers = response.data || [];
        const responsePage = response.meta?.current_page ?? page;

        setLoadedUsers((prev) => {
          if (responsePage === 1) {
            return responseUsers;
          }

          const existingIds = new Set(prev.map((user) => user.id));
          const merged = [...prev];
          responseUsers.forEach((user) => {
            if (!existingIds.has(user.id)) {
              merged.push(user);
            }
          });
          return merged;
        });

        setUserCache((prev) => {
          const next = new Map(prev);
          responseUsers.forEach((user) => {
            next.set(user.id, user);
          });
          return next;
        });

        if (response.meta) {
          setHasMore(response.meta.current_page < response.meta.last_page);
        } else {
          setHasMore(responseUsers.length >= USERS_PAGE_SIZE);
        }

        loadingMoreRef.current = false;
      },
      onError: () => {
        loadingMoreRef.current = false;
      },
    }),
    [page],
  );

  const { isLoading, isValidating } = useQuery<UsersListResponse>(
    "/users",
    queryParams,
    queryOptions,
  );

  useEffect(() => {
    const missingSelectedIds = value.filter((id) => !userCache.has(id));
    if (missingSelectedIds.length === 0) {
      return;
    }

    let cancelled = false;

    const fetchMissingUsers = async () => {
      const fetched = await Promise.all(
        missingSelectedIds.map(async (id) => {
          try {
            const response = await apiClient.get<{ data: User }>(`/users/${id}`);
            return response.data?.data || null;
          } catch {
            return null;
          }
        }),
      );

      if (cancelled) {
        return;
      }

      setUserCache((prev) => {
        const next = new Map(prev);
        fetched.forEach((user) => {
          if (user) {
            next.set(user.id, user);
          }
        });
        return next;
      });
    };

    void fetchMissingUsers();

    return () => {
      cancelled = true;
    };
  }, [userCache, value]);

  const selectedUserObjects = useMemo(
    () =>
      value
        .map((id) => userCache.get(id))
        .filter((user): user is User => Boolean(user)),
    [userCache, value],
  );

  useEffect(() => {
    onSelectedUsersChange?.(selectedUserObjects);
  }, [onSelectedUsersChange, selectedUserObjects]);

  // Get available users (not selected)
  const availableUsers = loadedUsers.filter((user) => !value.includes(user.id));

  const handleUserSelect = (userId: number) => {
    if (!value.includes(userId)) {
      onChange([...value, userId]);
    }
  };

  const handleUserRemove = (userId: number) => {
    onChange(value.filter((id) => id !== userId));
  };

  const handleUsersListScroll = (event: React.UIEvent<HTMLDivElement>) => {
    if (!hasMore || isLoading || isValidating || loadingMoreRef.current) {
      return;
    }

    const target = event.currentTarget;
    const reachedBottom =
      target.scrollTop + target.clientHeight >= target.scrollHeight - 20;

    if (!reachedBottom) {
      return;
    }

    loadingMoreRef.current = true;
    setPage((prev) => prev + 1);
  };

  // Content component to avoid duplication
  const renderContent = () => (
    <div
      className={cn(
        "space-y-6",
        showHeader &&
        "bg-card border border-x border-b border-border rounded-b-2xl -mt-px p-6 animate-in slide-in-from-top-2",
      )}
    >
      {/* Search Input */}
      <div className="relative">
        <Search className="absolute end-3 top-1/2 -translate-y-1/2 size-4 text-muted-foreground" />
        <Input
          type="text"
          placeholder="بحث"
          value={searchQuery}
          onChange={(e) => setSearchQuery(e.target.value)}
          className="pe-10"
        />
      </div>

      {/* Selected Users as Badges */}
      {selectedUserObjects.length > 0 && (
        <div className="flex flex-wrap gap-2">
          {selectedUserObjects.map((user) => (
            <Badge
              key={user.id}
              variant="secondary"
              className="h-8 px-3 gap-1 rounded-full bg-secondary"
            >
              <span className="text-sm font-medium">{user.name}</span>
              <button
                type="button"
                onClick={(e) => {
                  e.stopPropagation();
                  handleUserRemove(user.id);
                }}
              >
                <X className="size-4" />
              </button>
            </Badge>
          ))}
        </div>
      )}

      {/* Available Users List */}
      {availableUsers.length > 0 && (
        <div
          className="space-y-1 max-h-[200px] overflow-y-auto"
          onScroll={handleUsersListScroll}
        >
          {availableUsers.map((user) => (
            <button
              key={user.id}
              type="button"
              onClick={() => handleUserSelect(user.id)}
              className="w-full flex items-center gap-2 px-2 py-2 rounded-sm hover:bg-muted/50 transition-colors text-sm text-foreground"
            >
              <Avatar className="size-6 border-2 border-white">
                <AvatarImage src={user.avatar || undefined} alt={user.name} />
                <AvatarFallback />
              </Avatar>
              <span>{user.name}</span>
            </button>
          ))}
          {isValidating && (
            <p className="text-xs text-muted-foreground text-center py-2">
              جاري تحميل المزيد...
            </p>
          )}
        </div>
      )}

      {/* Empty State */}
      {loadedUsers.length === 0 && !isLoading && !isValidating && (
        <p className="text-sm text-muted-foreground text-center py-4">
          لا يوجد مستخدمين
        </p>
      )}
    </div>
  );

  // When showHeader is false, just render the content directly
  if (!showHeader) {
    return <div className="w-full">{renderContent()}</div>;
  }

  // Render selected users badges (used both when collapsed and expanded)
  const renderSelectedBadges = () => (
    selectedUserObjects.length > 0 && (
      <div className="flex flex-wrap gap-2">
        {selectedUserObjects.map((user) => (
          <Badge
            key={user.id}
            variant="secondary"
            className="h-8 px-3 gap-1 rounded-full bg-secondary"
          >
            <span className="text-sm font-medium">{user.name}</span>
            <button
              type="button"
              onClick={(e) => {
                e.stopPropagation();
                handleUserRemove(user.id);
              }}
            >
              <X className="size-4" />
            </button>
          </Badge>
        ))}
      </div>
    )
  );

  return (
    <div className="w-full">
      {/* Header */}
      <button
        type="button"
        onClick={() => setIsOpen(!isOpen)}
        className={cn(
          "w-full bg-card border border-border overflow-hidden transition-all",
          isOpen || selectedUserObjects.length > 0 ? "rounded-t-2xl" : "rounded-2xl"
        )}
      >
        <div className="flex items-center justify-between px-6 py-4">
          <div className="flex items-center gap-2">
            <span className="text-base font-semibold text-foreground">
              {label}
            </span>
            <span className="text-sm font-normal text-muted-foreground">
              {hint}
            </span>
          </div>
          <ChevronDown
            className={cn(
              "size-5 transition-transform text-foreground",
              isOpen && "rotate-180",
            )}
          />
        </div>
      </button>

      {/* Selected Users when collapsed */}
      {!isOpen && selectedUserObjects.length > 0 && (
        <div className="bg-card border border-t-0 border-border rounded-b-2xl px-6 pb-4">
          {renderSelectedBadges()}
        </div>
      )}

      {/* Expandable Content */}
      {isOpen && renderContent()}
    </div>
  );
}
