import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { toast } from "sonner";
import {
    Building2,
    Check,
    FolderKanban,
    Loader2,
    UserPlus,
    X,
} from "lucide-react";
import {
    projectMyInvitations,
    projectAcceptInvitation,
    projectRejectInvitation,
    workspaceMyInvitations,
    workspaceAcceptInvitationBySlug,
} from "@/client";
import type { InvitationResponse, MyWorkspaceInvitation } from "@/client";
import { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge";
import { getApiErrorMessage } from "@/lib/api-error";
import { useNavigate } from "react-router-dom";

function formatTime(dateStr: string): string {
    const d = new Date(dateStr);
    const now = new Date();
    const diff = now.getTime() - d.getTime();
    const minutes = Math.floor(diff / 60000);
    if (minutes < 1) return "just now";
    if (minutes < 60) return `${minutes}m ago`;
    const hours = Math.floor(minutes / 60);
    if (hours < 24) return `${hours}h ago`;
    const days = Math.floor(hours / 24);
    if (days < 7) return `${days}d ago`;
    return d.toLocaleDateString();
}

type UnifiedInvitation =
    | ({ type: "project" } & InvitationResponse)
    | ({ type: "workspace" } & MyWorkspaceInvitation);

function ProjectInvitationItem({
    inv,
    onAccept,
    onReject,
    isAccepting,
    isRejecting,
}: {
    inv: InvitationResponse;
    onAccept: () => void;
    onReject: () => void;
    isAccepting: boolean;
    isRejecting: boolean;
}) {
    return (
        <div className="flex items-start gap-3 px-4 py-4 border-b last:border-b-0 hover:bg-muted/50 transition-colors">
            <div className="flex-shrink-0 mt-0.5 h-8 w-8 rounded-full border bg-purple-500/10 text-purple-600 border-purple-500/20 flex items-center justify-center">
                <FolderKanban className="h-3.5 w-3.5" />
            </div>
            <div className="flex-1 min-w-0">
                <div className="flex items-start justify-between gap-2">
                    <div className="min-w-0">
                        <div className="flex items-center gap-2">
                            <p className="text-sm font-semibold truncate">Project Invitation</p>
                            <Badge variant="outline" className="text-xs bg-purple-500/10 text-purple-600 border-purple-500/20">
                                {inv.scope}
                            </Badge>
                        </div>
                        <p className="text-xs text-muted-foreground mt-0.5">
                            You&apos;ve been invited to join{" "}
                            <span className="font-medium text-foreground">{inv.project_name}</span>
                        </p>
                        <div className="flex items-center gap-2 mt-1.5">
                            {inv.invited_by_username && (
                                <span className="text-xs text-muted-foreground">
                                    by {inv.invited_by_username}
                                </span>
                            )}
                            <span className="text-xs text-muted-foreground">
                                {formatTime(inv.created_at)}
                            </span>
                        </div>
                    </div>
                    <div className="flex-shrink-0 flex items-center gap-2">
                        <Button
                            size="sm"
                            variant="outline"
                            className="h-8 text-xs gap-1 text-muted-foreground hover:text-foreground"
                            onClick={onReject}
                            disabled={isAccepting || isRejecting}
                        >
                            {isRejecting ? (
                                <Loader2 className="h-3 w-3 animate-spin" />
                            ) : (
                                <X className="h-3 w-3" />
                            )}
                            Decline
                        </Button>
                        <Button
                            size="sm"
                            variant="default"
                            className="h-8 text-xs gap-1"
                            onClick={onAccept}
                            disabled={isAccepting || isRejecting}
                        >
                            {isAccepting ? (
                                <Loader2 className="h-3 w-3 animate-spin" />
                            ) : (
                                <Check className="h-3 w-3" />
                            )}
                            Accept
                        </Button>
                    </div>
                </div>
            </div>
        </div>
    );
}

function WorkspaceInvitationItem({
    inv,
    onAccept,
    isAccepting,
}: {
    inv: MyWorkspaceInvitation;
    onAccept: () => void;
    isAccepting: boolean;
}) {
    return (
        <div className="flex items-start gap-3 px-4 py-4 border-b last:border-b-0 hover:bg-muted/50 transition-colors">
            <div className="flex-shrink-0 mt-0.5 h-8 w-8 rounded-full border bg-blue-500/10 text-blue-600 border-blue-500/20 flex items-center justify-center">
                <Building2 className="h-3.5 w-3.5" />
            </div>
            <div className="flex-1 min-w-0">
                <div className="flex items-start justify-between gap-2">
                    <div className="min-w-0">
                        <div className="flex items-center gap-2">
                            <p className="text-sm font-semibold truncate">Workspace Invitation</p>
                            <Badge variant="outline" className="text-xs bg-blue-500/10 text-blue-600 border-blue-500/20">
                                {inv.role}
                            </Badge>
                        </div>
                        <p className="text-xs text-muted-foreground mt-0.5">
                            You&apos;ve been invited to join workspace{" "}
                            <span className="font-medium text-foreground">{inv.workspace_name}</span>
                        </p>
                        <div className="flex items-center gap-2 mt-1.5">
                            {inv.invited_by_username && (
                                <span className="text-xs text-muted-foreground">
                                    by {inv.invited_by_username}
                                </span>
                            )}
                            <span className="text-xs text-muted-foreground">
                                {formatTime(inv.invited_at)}
                            </span>
                        </div>
                    </div>
                    <div className="flex-shrink-0">
                        <Button
                            size="sm"
                            variant="default"
                            className="h-8 text-xs gap-1"
                            onClick={onAccept}
                            disabled={isAccepting}
                        >
                            {isAccepting ? (
                                <Loader2 className="h-3 w-3 animate-spin" />
                            ) : (
                                <Check className="h-3 w-3" />
                            )}
                            Accept
                        </Button>
                    </div>
                </div>
            </div>
        </div>
    );
}

export default function InvitationsPage() {
    const queryClient = useQueryClient();
    const navigate = useNavigate();

    const { data: projectData, isLoading: projectLoading } = useQuery({
        queryKey: ["projectInvitations"],
        queryFn: async () => {
            const resp = await projectMyInvitations();
            return resp.data?.data ?? null;
        },
    });

    const { data: workspaceData, isLoading: workspaceLoading } = useQuery({
        queryKey: ["workspaceInvitations"],
        queryFn: async () => {
            const resp = await workspaceMyInvitations();
            return resp.data?.data ?? [];
        },
    });

    const acceptProjectMutation = useMutation({
        mutationFn: async (projectName: string) => {
            await projectAcceptInvitation({ path: { project_name: projectName } });
        },
        onSuccess: (_data, projectName) => {
            toast.success(`You've joined project: ${projectName}`);
            queryClient.invalidateQueries({ queryKey: ["projectInvitations"] });
            queryClient.invalidateQueries({ queryKey: ["me"] });
            navigate(`/project/${projectName}`);
        },
        onError: (err: unknown) => {
            toast.error(getApiErrorMessage(err, "Failed to accept invitation"));
        },
    });

    const rejectProjectMutation = useMutation({
        mutationFn: async (projectName: string) => {
            await projectRejectInvitation({ path: { project_name: projectName } });
        },
        onSuccess: (_data, projectName) => {
            toast.success(`Invitation to ${projectName} declined`);
            queryClient.invalidateQueries({ queryKey: ["projectInvitations"] });
        },
        onError: (err: unknown) => {
            toast.error(getApiErrorMessage(err, "Failed to decline invitation"));
        },
    });

    const acceptWorkspaceMutation = useMutation({
        mutationFn: async (slug: string) => {
            await workspaceAcceptInvitationBySlug({
                body: { slug },
            });
        },
        onSuccess: () => {
            toast.success("You've joined the workspace");
            queryClient.invalidateQueries({ queryKey: ["workspaceInvitations"] });
            queryClient.invalidateQueries({ queryKey: ["me"] });
        },
        onError: (err: unknown) => {
            toast.error(getApiErrorMessage(err, "Failed to accept invitation"));
        },
    });

    const projectInvitations: InvitationResponse[] = projectData?.invitations ?? [];
    const workspaceInvitations: MyWorkspaceInvitation[] = workspaceData ?? [];
    const total = projectInvitations.length + workspaceInvitations.length;

    const unified: UnifiedInvitation[] = [
        ...projectInvitations.map((inv) => ({ type: "project" as const, ...inv })),
        ...workspaceInvitations.map((inv) => ({ type: "workspace" as const, ...inv })),
    ].sort((a, b) => {
        const aTime = a.type === "project" ? a.created_at : a.invited_at;
        const bTime = b.type === "project" ? b.created_at : b.invited_at;
        return new Date(bTime).getTime() - new Date(aTime).getTime();
    });

    const isLoading = projectLoading || workspaceLoading;

    return (
        <div className="max-w-3xl mx-auto p-6 space-y-4">
            <div className="flex items-center justify-between">
                <div>
                    <h1 className="text-xl font-semibold flex items-center gap-2">
                        <UserPlus className="h-5 w-5" />
                        My Invitations
                    </h1>
                    <p className="text-sm text-muted-foreground mt-0.5">
                        {total > 0
                            ? `${total} pending invitation${total !== 1 ? "s" : ""}`
                            : "No pending invitations"}
                    </p>
                </div>
            </div>

            <div className="border rounded-lg bg-card overflow-hidden">
                {isLoading ? (
                    <div className="flex items-center justify-center h-48">
                        <Loader2 className="h-6 w-6 animate-spin text-muted-foreground" />
                    </div>
                ) : unified.length === 0 ? (
                    <div className="flex flex-col items-center justify-center h-48 text-muted-foreground">
                        <UserPlus className="h-10 w-10 mb-3 opacity-40" />
                        <p className="font-medium">No pending invitations</p>
                        <p className="text-sm mt-1">
                            Project and workspace invitations will appear here.
                        </p>
                    </div>
                ) : (
                    unified.map((inv) => {
                        if (inv.type === "project") {
                            return (
                                <ProjectInvitationItem
                                    key={`project-${inv.project_uid}`}
                                    inv={inv}
                                    onAccept={() => acceptProjectMutation.mutate(inv.project_name)}
                                    onReject={() => rejectProjectMutation.mutate(inv.project_name)}
                                    isAccepting={acceptProjectMutation.isPending}
                                    isRejecting={rejectProjectMutation.isPending}
                                />
                            );
                        } else {
                            return (
                                <WorkspaceInvitationItem
                                    key={`workspace-${inv.workspace_id}`}
                                    inv={inv}
                                    onAccept={() => acceptWorkspaceMutation.mutate(inv.workspace_slug)}
                                    isAccepting={acceptWorkspaceMutation.isPending}
                                />
                            );
                        }
                    })
                )}
            </div>
        </div>
    );
}
