"use client";

import { useState } from "react";
import { Menu } from "@headlessui/react";
import { signOut, useSession } from "next-auth/react";
import Link from "next/link";
import { useRouter } from "next/navigation";
import Image from "next/image";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { useToast } from "@/app/hooks/use-toast";
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogTitle,
} from "@/app/shadcn_components/ui/dialog";
import { Button } from "@/app/shadcn_components/ui/button";

type PendingInvitation = {
  invitationId: string;
  portfolioId: string;
  portfolioName: string;
  role: string;
  invitedByName: string | null;
  createdAt: string;
};

async function fetchPendingInvitations(): Promise<PendingInvitation[]> {
  const res = await fetch("/api/user/invitations");
  if (!res.ok) throw new Error("Failed to fetch invitations");
  const json = await res.json();
  const invitations = json?.invitations ?? [];
  return Array.isArray(invitations) ? invitations : [];
}

async function respondToInvitation(
  invitationId: string,
  action: "accept" | "decline",
): Promise<{ portfolioId?: string }> {
  const res = await fetch("/api/user/invitations", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ invitationId, action }),
  });
  if (!res.ok) {
    const msg = await res.text().catch(() => "");
    throw new Error(msg || `Failed to ${action} invitation`);
  }
  return res.json().catch(() => ({}));
}

const INVITATIONS_KEY = ["userInvitations"] as const;

function ProfileDropDown({ userImage }: { userImage: string }) {
  const { data: session } = useSession();
  const email = session?.user?.email ?? null;
  const isAuthenticated = !!session?.user;

  const queryClient = useQueryClient();
  const { toast } = useToast();
  const router = useRouter();
  const [acceptedInfo, setAcceptedInfo] = useState<{
    portfolioId: string;
    portfolioName: string;
  } | null>(null);

  const { data: invitations = [], isLoading } = useQuery({
    queryKey: INVITATIONS_KEY,
    queryFn: fetchPendingInvitations,
    enabled: isAuthenticated,
    refetchOnWindowFocus: false,
  });

  const pendingCount = invitations.length;

  const respondMutation = useMutation({
    mutationFn: ({
      invitationId,
      action,
    }: {
      invitationId: string;
      action: "accept" | "decline";
    }) => respondToInvitation(invitationId, action),

    onMutate: async ({ invitationId }) => {
      await queryClient.cancelQueries({ queryKey: INVITATIONS_KEY });
      const previous =
        queryClient.getQueryData<PendingInvitation[]>(INVITATIONS_KEY);
      queryClient.setQueryData<PendingInvitation[]>(INVITATIONS_KEY, (old) =>
        (old ?? []).filter((i) => i.invitationId !== invitationId),
      );
      return { previous };
    },
    onError: (err, vars, context) => {
      if (context?.previous) {
        queryClient.setQueryData(INVITATIONS_KEY, context.previous);
      }
      toast({
        title: `Couldn't ${vars.action} invitation`,
        description: err instanceof Error ? err.message : "Please try again.",
        variant: "destructive",
      });
    },
    onSuccess: (data, vars) => {
      const inv = invitations.find((i) => i.invitationId === vars.invitationId);
      if (vars.action === "accept") {
        const portfolioId = data?.portfolioId ?? inv?.portfolioId;
        const portfolioName = inv?.portfolioName ?? "the portfolio";
        // /home's server-rendered portfolio list won't pick up the new
        // membership without an explicit refresh; the API handler also calls
        // revalidatePath("/home") so any later navigation is fresh too.
        router.refresh();
        if (portfolioId) {
          setAcceptedInfo({ portfolioId, portfolioName });
        } else {
          toast({
            title: "Joined portfolio",
            description: `You now have access to ${portfolioName}.`,
          });
        }
      } else {
        const portfolioLabel = inv ? `the ${inv.portfolioName} portfolio` : "the portfolio";
        toast({
          title: "Invitation declined",
          description: `You've declined the invitation to ${portfolioLabel}.`,
        });
      }
    },
    onSettled: () => {
      queryClient.invalidateQueries({ queryKey: INVITATIONS_KEY });
    },
  });

  return (
    <>
    <Menu as="div" className="relative">
      <Menu.Button className="rounded-full relative">
        {userImage ? (
          <Image
            src={userImage}
            alt={"Profile"}
            className="inline rounded-full text-white"
            height={48}
            width={48}
          />
        ) : (
          <span className="inline-block h-12 w-12 overflow-hidden rounded-full bg-stone-100">
            <svg
              className="h-full w-full text-stone-300"
              fill="currentColor"
              viewBox="0 0 24 24"
            >
              <path d="M24 20.993V24H0v-2.996A14.977 14.977 0 0112.004 15c4.904 0 9.26 2.354 11.996 5.993zM16.002 8.999a4 4 0 11-8 0 4 4 0 018 0z" />
            </svg>
          </span>
        )}
        {pendingCount > 0 && (
          <span
            className="absolute -top-0.5 -right-0.5 min-w-[1.25rem] h-5 px-1 inline-flex items-center justify-center rounded-full bg-red-600 text-white text-[10px] font-bold ring-2 ring-brandblue"
            aria-label={`${pendingCount} pending invitation${pendingCount === 1 ? "" : "s"}`}
          >
            {pendingCount > 9 ? "9+" : pendingCount}
          </span>
        )}
      </Menu.Button>

      <Menu.Items className="z-[100] absolute right-0 mt-2 w-80 origin-top-right overflow-hidden rounded-md border bg-white shadow-lg focus:outline-none">
        {/* Signed-in identity */}
        {email && (
          <div className="px-4 py-3 border-b border-gray-100">
            <p className="text-[10px] uppercase tracking-wider text-gray-400 font-medium">
              Signed in as
            </p>
            <p className="text-sm text-gray-800 truncate" title={email}>
              {email}
            </p>
          </div>
        )}

        {/* Pending invitations */}
        {isAuthenticated && (
          <div className="border-b border-gray-100">
            <p className="px-4 pt-3 pb-1 text-[10px] uppercase tracking-wider text-gray-400 font-medium">
              Pending invitations
            </p>
            {isLoading ? (
              <p className="px-4 py-2 text-sm text-gray-500">Loading…</p>
            ) : invitations.length === 0 ? (
              <p className="px-4 py-2 text-sm text-gray-400">
                No pending invitations.
              </p>
            ) : (
              <ul className="max-h-72 overflow-y-auto">
                {invitations.map((inv) => (
                  <li
                    key={inv.invitationId}
                    className="px-4 py-3 border-t border-gray-50 first:border-t-0"
                  >
                    <p className="text-sm font-medium text-gray-800">
                      {inv.portfolioName}
                    </p>
                    <p className="text-xs text-gray-500 mb-2">
                      {inv.invitedByName
                        ? `Invited by ${inv.invitedByName}`
                        : "Invited"}{" "}
                      · <span className="capitalize">{inv.role}</span>
                    </p>
                    <div className="flex gap-2">
                      <button
                        type="button"
                        onClick={() =>
                          respondMutation.mutate({
                            invitationId: inv.invitationId,
                            action: "accept",
                          })
                        }
                        disabled={
                          respondMutation.isPending &&
                          respondMutation.variables?.invitationId ===
                            inv.invitationId
                        }
                        className="flex-1 px-3 py-1.5 rounded-md bg-brandblue text-white text-xs font-medium hover:bg-hoverblue disabled:opacity-50"
                      >
                        Accept
                      </button>
                      <button
                        type="button"
                        onClick={() =>
                          respondMutation.mutate({
                            invitationId: inv.invitationId,
                            action: "decline",
                          })
                        }
                        disabled={
                          respondMutation.isPending &&
                          respondMutation.variables?.invitationId ===
                            inv.invitationId
                        }
                        className="flex-1 px-3 py-1.5 rounded-md border border-gray-200 text-gray-600 text-xs font-medium hover:bg-gray-50 disabled:opacity-50"
                      >
                        Decline
                      </button>
                    </div>
                  </li>
                ))}
              </ul>
            )}
          </div>
        )}

        <Menu.Item>
          {({ active }) => (
            <Link
              href="/help"
              className={`flex px-4 py-2 text-sm text-gray-700 ${active ? "bg-gray-50" : ""}`}
            >
              Help
            </Link>
          )}
        </Menu.Item>
        <Menu.Item>
          {({ active }) => (
            <button
              type="button"
              onClick={() => signOut()}
              className={`w-full text-left flex px-4 py-2 text-sm text-gray-700 ${active ? "bg-gray-50" : ""}`}
            >
              Sign out
            </button>
          )}
        </Menu.Item>
      </Menu.Items>
    </Menu>

    <Dialog
      open={!!acceptedInfo}
      onOpenChange={(open) => {
        if (!open) setAcceptedInfo(null);
      }}
    >
      <DialogContent>
        <DialogHeader>
          <DialogTitle>
            You&apos;ve joined {acceptedInfo?.portfolioName}
          </DialogTitle>
          <DialogDescription>
            You now have access. Head over when you&apos;re ready.
          </DialogDescription>
        </DialogHeader>
        <DialogFooter>
          <Button variant="outline" onClick={() => setAcceptedInfo(null)}>
            Close
          </Button>
          <Button
            onClick={() => {
              if (acceptedInfo) {
                router.push(`/portfolio/${acceptedInfo.portfolioId}`);
              }
              setAcceptedInfo(null);
            }}
          >
            Go to {acceptedInfo?.portfolioName ?? "portfolio"}
          </Button>
        </DialogFooter>
      </DialogContent>
    </Dialog>
    </>
  );
}

export default ProfileDropDown;
