// src/components/accept-invitation.tsx
"use client";

import Link from "next/link";
import { useRouter } from "next/navigation";
import { useTranslations } from "next-intl";
import { useState } from "react";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { Card, CardContent } from "@/components/ui/card";
import { authClient } from "@/lib/auth-client";
import { persistActiveOrgAction } from "@/lib/org/active-org-action";
import { cn } from "@/lib/utils";

// Map org roles to translation keys for display.
const ROLE_KEYS: Record<string, "roleOwner" | "roleAdmin" | "roleStaff"> = {
  owner: "roleOwner",
  admin: "roleAdmin",
  member: "roleStaff",
};

export function AcceptInvitation({
  invitationId,
  organizationId,
  orgName,
  role,
  invitedEmail,
  currentEmail,
  loggedIn,
  mismatch,
  expiredOrInvalid,
  className,
  ...props
}: React.ComponentProps<"div"> & {
  invitationId: string;
  /** The invited org — set as the active org on accept so the new member
   *  immediately sees its sites (otherwise they land on their empty personal org). */
  organizationId?: string;
  // orgName / role / invitedEmail are only meaningful for the valid + matching
  // case; the invalid and mismatch cards ignore the irrelevant ones.
  orgName?: string;
  role?: string;
  invitedEmail?: string;
  currentEmail: string;
  loggedIn: boolean;
  mismatch: boolean;
  expiredOrInvalid: boolean;
}) {
  const t = useTranslations("Auth");
  const router = useRouter();
  const [pending, setPending] = useState<"accept" | "reject" | null>(null);
  const [error, setError] = useState<string | null>(null);
  // The org has no seat left (server hook rejected with SEAT_BLOCKED) —
  // rendered as a dedicated state, never as the raw error message.
  const [seatBlocked, setSeatBlocked] = useState(false);

  const roleLabel = (role: string): string => {
    const key = ROLE_KEYS[role];
    return key ? t(key) : role;
  };

  // Invalid / expired / cancelled → neutral dead-end with a way back.
  if (expiredOrInvalid) {
    return (
      <div className={cn("flex flex-col gap-6", className)} {...props}>
        <Card>
          <CardContent className="flex flex-col items-center gap-3 p-6 text-center md:p-8">
            <h1 className="font-bold text-2xl">
              {t("invitationUnavailableTitle")}
            </h1>
            <p className="text-balance text-muted-foreground">
              {t("invitationUnavailableBody")}
            </p>
            <Link
              href="/keywords/reservoir"
              className="text-sm underline underline-offset-4"
            >
              {t("goToApp")}
            </Link>
          </CardContent>
        </Card>
      </div>
    );
  }

  // Not signed in yet → route to login/signup, returning here afterwards (and
  // prefilling the invited address so a new account matches the invite).
  if (!loggedIn) {
    const next = encodeURIComponent(`/accept-invitation/${invitationId}`);
    const emailQ = invitedEmail
      ? `&email=${encodeURIComponent(invitedEmail)}`
      : "";
    return (
      <div className={cn("flex flex-col gap-6", className)} {...props}>
        <Card>
          <CardContent className="flex flex-col items-center gap-4 p-6 text-center md:p-8">
            <h1 className="font-bold text-2xl">{t("invitedTitle")}</h1>
            <p className="text-balance text-muted-foreground">
              {t.rich("invitedJoinAs", {
                orgName: () => (
                  <span className="font-medium text-foreground">{orgName}</span>
                ),
                role: () => (
                  <Badge variant="secondary" className="align-middle">
                    {roleLabel(role ?? "member")}
                  </Badge>
                ),
              })}{" "}
              {invitedEmail
                ? t.rich("invitedSignInPrompt", {
                    email: () => (
                      <span className="font-medium text-foreground">
                        {invitedEmail}
                      </span>
                    ),
                  })
                : t("invitedSignInPromptNoEmail")}
            </p>
            <div className="flex w-full flex-col gap-2 sm:flex-row sm:justify-center">
              <Button asChild>
                <Link href={`/signup?next=${next}${emailQ}`}>
                  {t("createAccountLink")}
                </Link>
              </Button>
              <Button asChild variant="outline">
                <Link href={`/login?next=${next}${emailQ}`}>
                  {t("signInLink")}
                </Link>
              </Button>
            </div>
          </CardContent>
        </Card>
      </div>
    );
  }

  // Logged in as a different address than the invite was sent to.
  if (mismatch) {
    return (
      <div className={cn("flex flex-col gap-6", className)} {...props}>
        <Card>
          <CardContent className="flex flex-col items-center gap-3 p-6 text-center md:p-8">
            <h1 className="font-bold text-2xl">{t("wrongAccountTitle")}</h1>
            <p className="text-balance text-muted-foreground">
              {t.rich("wrongAccountBody", {
                invitedEmail: () => (
                  <span className="font-medium text-foreground">
                    {invitedEmail}
                  </span>
                ),
                currentEmail: () => (
                  <span className="font-medium text-foreground">
                    {currentEmail}
                  </span>
                ),
              })}
            </p>
            <Link
              href="/login"
              className="text-sm underline underline-offset-4"
            >
              {t("signInWithAnotherAccount")}
            </Link>
          </CardContent>
        </Card>
      </div>
    );
  }

  async function accept() {
    setError(null);
    setPending("accept");
    const res = await authClient.organization.acceptInvitation({
      invitationId,
    });
    if (res.error) {
      setPending(null);
      if (
        res.error.code === "SEAT_BLOCKED" ||
        res.error.message === "SEAT_BLOCKED"
      ) {
        setSeatBlocked(true);
        return;
      }
      setError(res.error.message ?? t("acceptFailed"));
      return;
    }
    // Switch the active org to the one just joined, so the reservoir shows THIS
    // org's sites instead of the member's empty personal org.
    if (organizationId) {
      await authClient.organization.setActive({ organizationId });
      // Persist so the next login keeps them on the org they just joined.
      await persistActiveOrgAction(organizationId);
    }
    router.push("/keywords/reservoir");
  }

  async function reject() {
    setError(null);
    setPending("reject");
    const res = await authClient.organization.rejectInvitation({
      invitationId,
    });
    if (res.error) {
      setPending(null);
      setError(res.error.message ?? t("rejectFailed"));
      return;
    }
    router.push("/");
  }

  // Acceptance was rejected because the org has no seat left: the invitation
  // stays pending and the owner was emailed — point the member at their own
  // workspace meanwhile.
  if (seatBlocked) {
    return (
      <div className={cn("flex flex-col gap-6", className)} {...props}>
        <Card>
          <CardContent className="flex flex-col items-center gap-4 p-6 text-center md:p-8">
            <h1 className="font-bold text-2xl">{t("seatBlockedTitle")}</h1>
            <p className="text-balance text-muted-foreground">
              {t("seatBlockedBody", { org: orgName ?? "" })}
            </p>
            <p className="text-balance text-muted-foreground">
              {t("seatBlockedMeanwhile")}
            </p>
            <Button asChild>
              <Link href="/keywords/reservoir">{t("goToApp")}</Link>
            </Button>
          </CardContent>
        </Card>
      </div>
    );
  }

  // Valid + email matches → the actionable accept/refuse card.
  return (
    <div className={cn("flex flex-col gap-6", className)} {...props}>
      <Card>
        <CardContent className="flex flex-col items-center gap-4 p-6 text-center md:p-8">
          <h1 className="font-bold text-2xl">{t("youWereInvitedTitle")}</h1>
          <p className="text-balance text-muted-foreground">
            {t.rich("youWereInvitedBody", {
              orgName: () => (
                <span className="font-medium text-foreground">{orgName}</span>
              ),
              role: () => (
                <Badge variant="secondary" className="align-middle">
                  {roleLabel(role ?? "member")}
                </Badge>
              ),
            })}
          </p>
          {error ? (
            <p className="text-destructive text-sm" role="alert">
              {error}
            </p>
          ) : null}
          <div className="flex w-full flex-col gap-2 sm:flex-row sm:justify-center">
            <Button onClick={accept} disabled={pending !== null}>
              {pending === "accept" ? "…" : t("acceptButton")}
            </Button>
            <Button
              variant="outline"
              onClick={reject}
              disabled={pending !== null}
            >
              {pending === "reject" ? "…" : t("rejectButton")}
            </Button>
          </div>
        </CardContent>
      </Card>
    </div>
  );
}
