"use client";

import * as React from "react";
import { Check, Copy, Loader2, X } from "lucide-react";

import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import {
  Sheet,
  SheetContent,
  SheetDescription,
  SheetHeader,
  SheetTitle,
  SheetTrigger,
} from "@/components/ui/sheet";
import { api } from "@/lib/trpc";
import { cn } from "@/lib/utils";

type InviteRole = "admin" | "member";

interface InviteDialogProps {
  workspaceSlug: string;
  /** Children render as the trigger; default is a primary "Invite" button. */
  children?: React.ReactNode;
}

/**
 * Owner/admin-only modal for inviting a teammate by email. Returns the
 * accept URL on success so the inviter can copy/paste it into chat / DM
 * until the transactional email send is wired up (filed follow-up).
 *
 * The email input is a plain `<Input>` in this task; the smart recipient
 * autocomplete from `Task-invite-recipient-autocomplete` will swap it for
 * a combobox in a separate commit.
 */
export function InviteDialog({ workspaceSlug, children }: InviteDialogProps) {
  const utils = api.useUtils();
  const [open, setOpen] = React.useState(false);
  const [email, setEmail] = React.useState("");
  const [role, setRole] = React.useState<InviteRole>("member");
  const [acceptUrl, setAcceptUrl] = React.useState<string | null>(null);
  const [reused, setReused] = React.useState(false);
  const [copied, setCopied] = React.useState(false);
  const [error, setError] = React.useState<string | null>(null);

  const createMut = api.invites.create.useMutation({
    onSuccess: async (result) => {
      setError(null);
      setReused(result.reused);
      const fullUrl = result.acceptUrl.startsWith("/")
        ? `${window.location.origin}${result.acceptUrl}`
        : result.acceptUrl;
      setAcceptUrl(fullUrl);
      setCopied(false);
      await utils.invites.list.invalidate({ workspace: workspaceSlug });
    },
    onError: (e) => {
      setError(e.message);
      setAcceptUrl(null);
    },
  });

  const reset = () => {
    setEmail("");
    setRole("member");
    setAcceptUrl(null);
    setReused(false);
    setCopied(false);
    setError(null);
    createMut.reset();
  };

  const onSubmit = (e: React.FormEvent) => {
    e.preventDefault();
    if (!email.trim()) {
      setError("Email is required");
      return;
    }
    createMut.mutate({
      workspace: workspaceSlug,
      email: email.trim().toLowerCase(),
      role,
    });
  };

  const onCopy = async () => {
    if (!acceptUrl) return;
    try {
      await navigator.clipboard.writeText(acceptUrl);
      setCopied(true);
      window.setTimeout(() => setCopied(false), 2000);
    } catch {
      // Clipboard API can fail in non-secure contexts; fall back to selecting
      // the input so the user can copy manually.
      const input = document.getElementById("invite-accept-url") as
        | HTMLInputElement
        | null;
      input?.select();
    }
  };

  return (
    <Sheet
      open={open}
      onOpenChange={(next) => {
        setOpen(next);
        if (!next) reset();
      }}
    >
      <SheetTrigger asChild>
        {children ?? <Button type="button">Invite</Button>}
      </SheetTrigger>
      <SheetContent side="right" className="w-full sm:max-w-md">
        <SheetHeader>
          <SheetTitle>Invite a teammate</SheetTitle>
          <SheetDescription>
            They&apos;ll get a private link to join this workspace. The link
            expires in 14 days.
          </SheetDescription>
        </SheetHeader>

        {acceptUrl ? (
          <div className="mt-6 space-y-4">
            <div className="rounded-md border border-emerald-200 bg-emerald-50 p-3 text-sm text-emerald-700 dark:border-emerald-900/50 dark:bg-emerald-950/30 dark:text-emerald-300">
              {reused
                ? "An invite for this email already exists. Here's the link:"
                : "Invite created. Share this link with them:"}
            </div>

            <div className="space-y-1.5">
              <label
                htmlFor="invite-accept-url"
                className="text-xs font-medium text-muted-foreground"
              >
                Accept link
              </label>
              <div className="flex items-center gap-2">
                <Input
                  id="invite-accept-url"
                  value={acceptUrl}
                  readOnly
                  onFocus={(e) => e.currentTarget.select()}
                  className="font-mono text-xs"
                />
                <Button
                  type="button"
                  variant="outline"
                  size="icon"
                  onClick={onCopy}
                  aria-label={copied ? "Copied" : "Copy invite link"}
                >
                  {copied ? (
                    <Check className="size-4 text-emerald-600" />
                  ) : (
                    <Copy className="size-4" />
                  )}
                </Button>
              </div>
              <p className="text-[11px] text-muted-foreground">
                Email delivery isn&apos;t wired up yet. Paste this link to them
                directly until it is.
              </p>
            </div>

            <div className="flex justify-end gap-2 pt-2">
              <Button type="button" variant="ghost" onClick={reset}>
                Invite another
              </Button>
              <Button type="button" onClick={() => setOpen(false)}>
                Done
              </Button>
            </div>
          </div>
        ) : (
          <form onSubmit={onSubmit} className="mt-6 space-y-5">
            <div className="space-y-1.5">
              <label htmlFor="invite-email" className="text-xs font-medium">
                Email
              </label>
              <Input
                id="invite-email"
                type="email"
                autoComplete="off"
                placeholder="alex@example.com"
                value={email}
                onChange={(e) => setEmail(e.target.value)}
                required
                disabled={createMut.isPending}
              />
            </div>

            <div className="space-y-1.5">
              <label htmlFor="invite-role" className="text-xs font-medium">
                Role
              </label>
              <select
                id="invite-role"
                value={role}
                onChange={(e) => setRole(e.target.value as InviteRole)}
                disabled={createMut.isPending}
                className={cn(
                  "h-9 w-full rounded-md border border-input bg-background px-3 py-1 text-sm",
                  "focus:outline-none focus:ring-2 focus:ring-ring",
                )}
              >
                <option value="member">Member — can use the workspace</option>
                <option value="admin">Admin — can also manage people</option>
              </select>
              <p className="text-[11px] text-muted-foreground">
                Ownership transfers happen in a separate flow, not via invite.
              </p>
            </div>

            {error ? (
              <p
                className="flex items-start gap-2 text-sm text-destructive"
                role="alert"
              >
                <X className="mt-0.5 size-4 shrink-0" aria-hidden />
                <span>{error}</span>
              </p>
            ) : null}

            <div className="flex justify-end gap-2 pt-2">
              <Button
                type="button"
                variant="ghost"
                onClick={() => setOpen(false)}
                disabled={createMut.isPending}
              >
                Cancel
              </Button>
              <Button type="submit" disabled={createMut.isPending || !email.trim()}>
                {createMut.isPending ? (
                  <>
                    <Loader2 className="size-4 animate-spin" aria-hidden />
                    Sending…
                  </>
                ) : (
                  "Send invite"
                )}
              </Button>
            </div>
          </form>
        )}
      </SheetContent>
    </Sheet>
  );
}
