import { Link, Outlet, useLocation, useNavigate } from "react-router";
import {
  Bell,
  ChevronDown,
  Folder,
  Grid2X2,
  LayoutDashboard,
  Search,
  Sparkles,
  Star,
  Trash2,
  Users,
  Plus,
  Bot,
} from "lucide-react";
import { useState, useEffect, useCallback } from "react";
import { motion } from "motion/react";
import { cn } from "@/lib/utils";
import NavShell from "./rail";
import { workspaceColor, workspaceInitial } from "./shared";
import { useAuth } from "@/context/auth-context";
import { Button } from "@/components/ui/button";
import { client } from "@/client";
import type { ConversationWithSessionResponse } from "@/client/models/conversationWithSessionResponse";
import { Shimmer } from "@/components/ai-elements/shimmer";
import { usePersonalSessions, ensurePersonalSession } from "@/page/me/chat/use-personal-sessions";

function PersonalAvatar() {
  const { me } = useAuth();
  const name = me?.display_name || me?.username || "User";

  return (
    <span
      className={cn(
        "grid size-9 shrink-0 place-items-center overflow-hidden rounded-full bg-gradient-to-br text-sm font-semibold text-white",
        workspaceColor(name),
      )}
    >
      {me?.avatar_url ? (
        <img alt="" className="size-full object-cover" src={me.avatar_url} />
      ) : (
        workspaceInitial(name)
      )}
    </span>
  );
}

function PersonalModeSwitch() {
  const location = useLocation();
  const showAgent = location.pathname.startsWith("/me/chat");

  const modes = [
    { label: "Agent", to: "/me/chat", icon: <Sparkles className="size-4" />, active: showAgent },
    { label: "Personal", to: "/me", icon: <Grid2X2 className="size-4" />, active: !showAgent },
  ];

  return (
    <nav aria-label="Personal mode" className="grid grid-cols-2 gap-1 rounded-xl bg-muted/70 p-1">
      {modes.map((mode) => (
        <Link
          className={cn(
            "flex h-8 items-center justify-center gap-2 rounded-md text-sm font-semibold text-muted-foreground transition-colors hover:text-foreground",
            mode.active && "bg-card text-foreground shadow-sm ring-1 ring-border",
          )}
          key={mode.to}
          to={mode.to}
        >
          {mode.icon}
          <span className="truncate">{mode.label}</span>
        </Link>
      ))}
    </nav>
  );
}

function PersonalNavLink({ item, active }: { item: { label: string; to: string; icon: React.ReactNode; badge?: string }; active: boolean }) {
  return (
    <Link
      className={cn(
        "flex h-9 items-center gap-2.5 rounded-lg px-3 text-sm font-medium text-muted-foreground transition-colors hover:bg-accent hover:text-foreground",
        active && "bg-accent text-foreground",
      )}
      to={item.to}
    >
      <span className="text-muted-foreground [&_svg]:size-4">{item.icon}</span>
      <span className="min-w-0 flex-1 truncate">{item.label}</span>
      {item.badge && (
        <span className="rounded-full bg-card px-2 py-0.5 text-xs text-muted-foreground">{item.badge}</span>
      )}
    </Link>
  );
}

// ---- Agent Chat Section (replaces DMs) ----

function formatTime(iso: string | null | undefined): string {
  if (!iso) return "";
  const d = new Date(iso);
  const now = new Date();
  const diffMs = now.getTime() - d.getTime();
  const diffDays = Math.floor(diffMs / 86_400_000);
  if (diffDays === 0) return d.toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" });
  if (diffDays === 1) return "Yesterday";
  if (diffDays < 7) return `${diffDays}d ago`;
  return d.toLocaleDateString([], { month: "short", day: "numeric" });
}

const SKELETON_COUNT = 3;

function AgentChatSidebar() {
  const navigate = useNavigate();
  const location = useLocation();
  const conversationId = location.pathname.split("/me/chat/")[1] || "";
  const { loading: sessionsLoading, sessionsRef, personalSessionIds } = usePersonalSessions();

  const [conversations, setConversations] = useState<ConversationWithSessionResponse[]>([]);
  const [loading, setLoading] = useState(true);

  const loadConversations = useCallback(async () => {
    if (personalSessionIds.size === 0) return;
    try {
      setLoading(true);
      const res = await client.agentListAllConversations().catch(() => ({
        data: [] as ConversationWithSessionResponse[],
      }));
      const sorted = [...res.data]
        .filter((c) => personalSessionIds.has(c.session_id))
        .sort((a, b) => {
        const da = a.last_message_at ? new Date(a.last_message_at).getTime() : new Date(a.created_at).getTime();
        const db = b.last_message_at ? new Date(b.last_message_at).getTime() : new Date(b.created_at).getTime();
        return db - da;
      });
      setConversations(sorted);
    } finally {
      setLoading(false);
    }
  }, [personalSessionIds]);

  // Only load conversations after personal sessions are known
  useEffect(() => {
    if (!sessionsLoading) {
      loadConversations();
    }
  }, [sessionsLoading, loadConversations]);

  const handleNewChat = useCallback(async () => {
    const sessionId = await ensurePersonalSession(sessionsRef.current);
    if (!sessionId) return;

    try {
      const res = await client.agentCreateConversation(sessionId, { title: "New Chat" });
      const conv = res.data as unknown as ConversationWithSessionResponse;
      setConversations((prev) => [conv, ...prev]);
      navigate(`/me/chat/${conv.id}`);
    } catch {
      // Silently fail.
    }
  }, [sessionsRef, navigate]);

  const handleDelete = useCallback(
    async (id: string) => {
      try {
        await client.agentDeleteConversation(id);
        if (conversationId === id) {
          navigate("/me/chat");
        }
        setConversations((prev) => prev.filter((c) => c.id !== id));
      } catch {
        // Deletion failed.
      }
    },
    [conversationId, navigate],
  );

  return (
    <div className="flex flex-col">
      <div className="mb-2 flex items-center justify-between px-0.5 py-1">
        <div className="flex items-center gap-2">
          <span className="text-xs font-semibold uppercase tracking-[0.06em] text-muted-foreground">
            Chats
          </span>
        </div>
        <motion.button
          type="button"
          whileHover={{ scale: 1.05 }}
          whileTap={{ scale: 0.92 }}
          className="inline-flex size-6 cursor-pointer items-center justify-center rounded-md bg-muted/60 text-muted-foreground/60 transition-colors hover:bg-primary/10 hover:text-primary focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
          onClick={handleNewChat}
          aria-label="New chat"
        >
          <Plus className="size-3" aria-hidden="true" />
        </motion.button>
      </div>
      {loading ? (
        <div className="space-y-1">
          {Array.from({ length: SKELETON_COUNT }).map((_, i) => (
            <div className="h-9 rounded-lg px-2.5 py-2" key={i}>
              <Shimmer duration={1.8} spread={1.5}>
                {"\u00A0".repeat(24 + i * 6)}
              </Shimmer>
            </div>
          ))}
        </div>
      ) : conversations.length === 0 ? (
        <div className="flex flex-col items-center justify-center gap-2 py-8 text-center">
          <div className="grid size-10 place-items-center rounded-xl bg-muted/30">
            <Bot className="size-4 text-muted-foreground/25" />
          </div>
          <p className="text-[11px] text-muted-foreground/40">
            Click + to start a chat
          </p>
        </div>
      ) : (
        <div className="space-y-0.5">
          {conversations.map((conv) => {
            const active = conversationId === conv.id;
            const initials = (conv.title || "AI").slice(0, 2).toUpperCase();
            return (
              <div
                role="button"
                tabIndex={0}
                key={conv.id}
                aria-current={active ? "page" : undefined}
                aria-label={conv.title || "Untitled chat"}
                className={cn(
                  "group relative flex w-full cursor-pointer items-center gap-2.5 rounded-lg px-2.5 py-2 text-left transition-[background-color,color,box-shadow] duration-200 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
                  active
                    ? "bg-primary/[0.08] text-foreground ring-1 ring-primary/15"
                    : "text-muted-foreground hover:bg-accent/50 hover:text-foreground hover:shadow-sm",
                )}
                onClick={() => navigate(`/me/chat/${conv.id}`)}
                onKeyDown={(e) => {
                  if (e.key === "Enter" || e.key === " ") {
                    e.preventDefault();
                    navigate(`/me/chat/${conv.id}`);
                  }
                }}
              >
                {active && (
                  <span className="absolute left-0 top-1/2 h-5 w-[3px] -translate-y-1/2 rounded-r-full bg-primary/70" />
                )}
                <span
                  className={cn(
                    "grid size-7 shrink-0 place-items-center rounded-lg text-[10px] font-bold transition-colors",
                    active
                      ? "bg-primary/15 text-primary/70"
                      : "bg-muted/60 text-muted-foreground/50 group-hover:bg-primary/10 group-hover:text-primary/60",
                  )}
                  aria-hidden="true"
                >
                  {initials}
                </span>
                <div className="min-w-0 flex-1">
                  <div className="flex items-center justify-between gap-1.5">
                    <span className="truncate text-[12px] font-medium leading-tight">
                      {conv.title?.slice(0, 28) || "Untitled"}
                    </span>
                    <span className="shrink-0 text-[10px] tabular-nums text-muted-foreground/40">
                      {formatTime(conv.last_message_at || conv.created_at)}
                    </span>
                  </div>
                </div>
                <button
                  type="button"
                  className="shrink-0 cursor-pointer rounded-md p-1 text-muted-foreground/30 opacity-0 transition-[background-color,color,opacity] duration-200 hover:bg-destructive/10 hover:text-destructive focus-visible:opacity-100 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring group-hover:opacity-100"
                  onClick={(e) => {
                    e.stopPropagation();
                    handleDelete(conv.id);
                  }}
                  aria-label={`Delete chat "${conv.title || "Untitled"}"`}
                >
                  <Trash2 className="size-3" aria-hidden="true" />
                </button>
              </div>
            );
          })}
        </div>
      )}
    </div>
  );
}

function PersonalSidebar() {
  const { me } = useAuth();
  const location = useLocation();
  const showAgent = location.pathname.startsWith("/me/chat");

  const personalItems = [
    { label: "Overview", to: "/me", icon: <LayoutDashboard /> },
    { label: "Repositories", to: "/me/repos", icon: <Folder /> },
    { label: "Notifications", to: "/me/notifications", icon: <Bell />, badge: (me?.has_unread_notifications ?? 0) > 0 ? String(me?.has_unread_notifications ?? 0) : undefined },
  ];

  const socialItems = [
    { label: "Stars", to: "/me/stars", icon: <Star /> },
    { label: "Following", to: "/me/following", icon: <Users /> },
  ];

  return (
    <aside className="flex h-full w-[240px] shrink-0 flex-col overflow-hidden border-r border-border bg-sidebar">
      <header className="flex h-[48px] shrink-0 items-center gap-3 border-b border-border px-4">
        <PersonalAvatar />
        <button aria-label="Personal menu" className="flex min-w-0 flex-1 items-center gap-2 rounded-lg text-left text-base font-semibold text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring/30" type="button">
          <span className="truncate">{me?.display_name || me?.username || "User"}</span>
          <ChevronDown className="size-4 shrink-0 text-muted-foreground" />
        </button>
        <Button className="size-8 text-muted-foreground" size="icon" variant="ghost">
          <Search className="size-4" />
        </Button>
      </header>

      <div className="min-h-0 flex-1 overflow-y-auto overscroll-contain px-3 py-4">
        <div className="mb-4">
          <PersonalModeSwitch />
        </div>

        {showAgent ? (
          <section className="mb-5">
            <AgentChatSidebar />
          </section>
        ) : (
          <>
            <section className="mb-5">
              <div className="mb-2 flex w-full items-center justify-between px-2 text-xs font-semibold uppercase tracking-[0.08em] text-muted-foreground">
                Personal
              </div>
              <nav className="space-y-1">
                {personalItems.map((item) => (
                  <PersonalNavLink
                    item={item}
                    active={location.pathname === item.to}
                    key={item.to}
                  />
                ))}
              </nav>
            </section>

            <section className="mb-5">
              <div className="mb-2 flex w-full items-center justify-between px-2 text-xs font-semibold uppercase tracking-[0.08em] text-muted-foreground">
                Social
              </div>
              <nav className="space-y-1">
                {socialItems.map((item) => (
                  <PersonalNavLink
                    item={item}
                    active={location.pathname === item.to}
                    key={item.to}
                  />
                ))}
              </nav>
            </section>
          </>
        )}
      </div>
    </aside>
  );
}

export function PersonalShell() {
  return (
    <NavShell>
      <div className="flex h-full overflow-hidden">
        <PersonalSidebar />
        <main className="flex min-w-0 flex-1 flex-col overflow-hidden bg-background">
          <div className="flex h-[48px] shrink-0 items-center border-b border-border px-6" />
          <div className="min-h-0 flex-1 overflow-y-auto overscroll-contain">
            <Outlet />
          </div>
        </main>
      </div>
    </NavShell>
  );
}
