import { useMemo, useState, createContext, useContext } from "react";
import { Link, Outlet, useLocation, useParams, useSearchParams } from "react-router";
import {
  Bell,
  ChevronDown,
  ChevronRight,
  Folder,
  GitPullRequest,
  Hash,
  Home,
  Lock,
  Plus,
  Search,
  Settings,
  Users,
  X,
} from "lucide-react";
import { useQuery, useQueryClient } from "@tanstack/react-query";

import { api, client } from "@/client";
import { Button } from "@/components/ui/button";
import { CommandPalette } from "@/components/CommandPalette";
import RoomCreateDialog from "@/page/workspace/channel/room-create-dialog";
import NavShell from "./rail";
import { ShellNavLink } from "./shared";
import { cn } from "@/lib/utils";
import { TooltipProvider } from "@/components/ui/tooltip";
import { WorkspaceAvatar, WorkspaceModeSwitch } from "./workspace-sidebar-inner";
import { WorkplanChatSidebar } from "@/page/workspace/workplan/chat-sidebar";

/* ------------------------------------------------------------------ */
/*  Panel context                                                      */
/* ------------------------------------------------------------------ */

type WorkspaceMember = {
  id: string;
  username: string;
  display_name: string;
  avatar_url: string;
};

type PanelContextValue = {
  showMembers: boolean;
  toggleMembers: () => void;
  closeMembers: () => void;
  showSearch: boolean;
  toggleSearch: () => void;
  closeSearch: () => void;
  members: WorkspaceMember[];
  membersLoading: boolean;
};

const PanelContext = createContext<PanelContextValue>({
  showMembers: false,
  toggleMembers: () => {},
  closeMembers: () => {},
  showSearch: false,
  toggleSearch: () => {},
  closeSearch: () => {},
  members: [],
  membersLoading: false,
});

export const usePanelContext = () => useContext(PanelContext);

/* ------------------------------------------------------------------ */
/*  Types                                                              */
/* ------------------------------------------------------------------ */

type ChannelItem = {
  id: string;
  name: string;
  topic?: string | null;
  room_type: string;
  is_private: boolean;
  category?: string | null;
  workspace_id: string;
};

type CategoryItem = {
  id: string;
  name: string;
  position: number;
};

/* ------------------------------------------------------------------ */
/*  Channel Link                                                       */
/* ------------------------------------------------------------------ */

function ChannelLink({
  channel,
  projectName,
}: {
  channel: ChannelItem;
  projectName: string;
}) {
  const location = useLocation();
  const to = `/${projectName}/channel/${channel.id}`;
  const active = location.pathname === to;

  return (
    <Link
      className={cn(
        "group flex h-[36px] items-center gap-2 rounded-lg px-2.5 text-[13px] transition-[background-color,color,box-shadow] duration-150",
        active
          ? "bg-primary/[0.08] font-semibold text-foreground ring-1 ring-primary/10"
          : "text-muted-foreground/70 hover:bg-accent/50 hover:text-foreground",
      )}
      to={to}
    >
      <span
        className={cn(
          "shrink-0 transition-colors duration-150",
          active ? "text-primary/70" : "text-muted-foreground/50 group-hover:text-muted-foreground/70",
        )}
      >
        <Hash className="size-[15px]" />
      </span>
      <span className="min-w-0 flex-1 truncate">{channel.name}</span>
      {channel.is_private && (
        <Lock className="size-3 shrink-0 text-muted-foreground/30" />
      )}
    </Link>
  );
}

/* ------------------------------------------------------------------ */
/*  Channel Category Group                                             */
/* ------------------------------------------------------------------ */

function ChannelCategoryGroup({
  name,
  channels,
  projectName,
  defaultOpen,
}: {
  name: string;
  channels: ChannelItem[];
  projectName: string;
  defaultOpen: boolean;
}) {
  const [open, setOpen] = useState(defaultOpen);

  return (
    <div className="mb-0.5">
      <button
        className="flex h-7 w-full items-center gap-1.5 rounded-md px-1.5 text-[11px] font-semibold uppercase tracking-[0.06em] text-muted-foreground/50 transition-colors hover:text-muted-foreground/80 hover:bg-accent/40"
        onClick={() => setOpen((v) => !v)}
        type="button"
      >
        <ChevronRight
          className={cn(
            "size-3.5 shrink-0 transition-transform duration-200",
            open && "rotate-90",
          )}
        />
        <span className="flex-1 truncate text-left">{name}</span>
        <span className="text-[10px] tabular-nums text-muted-foreground/40">
          {channels.length}
        </span>
      </button>
      <div
        className={cn(
          "grid transition-[grid-template-rows] duration-200",
          open ? "grid-rows-[1fr]" : "grid-rows-[0fr]",
        )}
      >
        <div className="overflow-hidden">
          <div className="space-y-[1px] py-0.5">
            {channels.map((ch) => (
              <ChannelLink channel={ch} key={ch.id} projectName={projectName} />
            ))}
          </div>
        </div>
      </div>
    </div>
  );
}

/* ------------------------------------------------------------------ */
/*  WorkspaceSidebar                                                   */
/* ------------------------------------------------------------------ */

function WorkspaceSidebar() {
  const { projectName = "" } = useParams();
  const location = useLocation();
  const queryClient = useQueryClient();
  const { data: currentWorkspace } = useQuery({
    enabled: Boolean(projectName),
    queryKey: ["workspace", projectName],
    queryFn: async () => {
      const response = await client.workspaceGetWorkspace(projectName);
      return response.data;
    },
    retry: false,
  });

  const { data: channelsData } = useQuery<{
    rooms: ChannelItem[];
    categories: CategoryItem[];
    workspace_id?: string;
  }>({
    queryKey: ["channel", "rooms"],
    queryFn: async () => {
      const response = await api.get("/api/v1/ws/rooms");
      return response.data;
    },
    retry: false,
  });
  const channels = channelsData?.rooms ?? [];
  const categories = channelsData?.categories ?? [];

  // Group channels by category
  const { categorized, uncategorized } = useMemo(() => {
    const byCat = new Map<string | null, ChannelItem[]>();
    for (const ch of channels) {
      const key = ch.category ?? null;
      if (!byCat.has(key)) byCat.set(key, []);
      byCat.get(key)!.push(ch);
    }

    const catGroups: { id: string; name: string; channels: ChannelItem[] }[] = [];
    const flat: ChannelItem[] = [];

    if (categories.length > 0) {
      const sorted = [...categories].sort((a, b) => a.position - b.position);
      for (const cat of sorted) {
        const catChannels = byCat.get(cat.id);
        if (catChannels && catChannels.length > 0) {
          catGroups.push({ id: cat.id, name: cat.name, channels: catChannels });
          byCat.delete(cat.id);
        }
      }
    }

    for (const [, chs] of byCat) {
      if (chs.length > 0) flat.push(...chs);
    }

    return { categorized: catGroups, uncategorized: flat };
  }, [channels, categories]);

  const workspaceId =
    channels[0]?.workspace_id ?? channelsData?.workspace_id ?? "";
  const refreshChannels = () =>
    queryClient.invalidateQueries({ queryKey: ["channel", "rooms"] });

  const showChannel =
    location.pathname === `/${projectName}/channel` ||
    location.pathname.startsWith(`/${projectName}/channel/`) ||
    location.pathname === `/${projectName}/chat` ||
    location.pathname.startsWith(`/${projectName}/chat/`);

  return (
    <aside className="flex h-full w-[240px] shrink-0 flex-col overflow-hidden border-r border-border bg-sidebar">
      {/* Header */}
      <header className="flex h-[48px] shrink-0 items-center gap-2.5 border-b border-border px-4">
        <WorkspaceAvatar workspace={currentWorkspace} />
        <button aria-label="Workspace menu" className="flex min-w-0 flex-1 items-center gap-1.5 rounded-lg text-left focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring/30" type="button">
          <span className="truncate text-sm font-semibold text-foreground">
            {currentWorkspace?.name ?? projectName}
          </span>
          <ChevronDown className="size-3.5 shrink-0 text-muted-foreground/40" />
        </button>
        <Button
          aria-label="Search workspace"
          className="size-8 text-muted-foreground/30 hover:bg-accent/50 hover:text-muted-foreground"
          size="icon"
          variant="ghost"
        >
          <Search className="size-[15px]" />
        </Button>
      </header>

      <div className="min-h-0 flex-1 overflow-y-auto overscroll-contain px-2 py-3">
        <div className="mb-5">
          <WorkspaceModeSwitch projectName={projectName} />
        </div>

        {showChannel ? (
          <section className="mb-5">
            {/* Channel list header */}
            <div className="mb-2 flex items-center justify-between px-1.5">
              <span className="text-[11px] font-semibold uppercase tracking-[0.08em] text-muted-foreground/50">
                Channels
              </span>
            </div>

            {/* Uncategorized channels */}
            <div className="space-y-[1px] py-0.5">
              {uncategorized.map((ch) => (
                <ChannelLink channel={ch} key={ch.id} projectName={projectName} />
              ))}
            </div>

            {/* Categorized channels */}
            {categorized.map((group) => (
              <ChannelCategoryGroup
                channels={group.channels}
                defaultOpen={true}
                key={group.id}
                name={group.name}
                projectName={projectName}
              />
            ))}

            {/* Add channel button */}
            <RoomCreateDialog
              categories={
                categories as unknown as {
                  id: string;
                  name: string;
                  position: number;
                }[]
              }
              onCreated={refreshChannels}
              workspaceId={workspaceId}
            >
              <div className="mt-1.5 flex h-[36px] w-full cursor-pointer items-center gap-2 rounded-lg px-2 text-[13px] text-muted-foreground/60 transition-[background-color,color] duration-150 hover:bg-accent/50 hover:text-muted-foreground">
                <Plus className="size-[15px] shrink-0" />
                <span>Add channel</span>
              </div>
            </RoomCreateDialog>
          </section>
        ) : (
          <>
            <section className="mb-5">
              <div className="mb-2 flex w-full items-center justify-between px-2 text-[11px] font-semibold uppercase tracking-[0.08em] text-muted-foreground/35">
                Workplan
                <ChevronDown className="size-3.5" />
              </div>
              <nav className="space-y-[1px]">
                <ShellNavLink
                  item={{
                    label: "Repository",
                    to: `/${projectName}/repos`,
                    icon: <Folder />,
                  }}
                />
                <ShellNavLink
                  item={{
                    label: "Issues",
                    to: `/${projectName}/issues`,
                    icon: <GitPullRequest />,
                  }}
                />
              </nav>
            </section>
            <section className="mb-5">
              <WorkplanChatSidebar />
            </section>
          </>
        )}
      </div>

      {/* Settings pinned at bottom (Workplan mode only) */}
      {!showChannel && (
        <div className="shrink-0 border-t border-border/30 px-3 py-2">
          <ShellNavLink
            item={{
              label: "Settings",
              to: `/${projectName}/settings`,
              icon: <Settings />,
            }}
          />
        </div>
      )}
    </aside>
  );
}

/* ------------------------------------------------------------------ */
/*  TopBar                                                             */
/* ------------------------------------------------------------------ */

function TopBar() {
  const { projectName = "" } = useParams();
  const location = useLocation();
  const panel = usePanelContext();

  const segments = location.pathname.split("/").filter(Boolean);
  const isRepo = segments[1] === "repo" && segments.length >= 3;
  const isChannel = segments[1] === "channel" && segments.length >= 3;
  const roomId = isChannel ? segments[2] : null;

  const { data: channelsData } = useQuery<{
    rooms: ChannelItem[];
    categories: CategoryItem[];
  }>({
    queryKey: ["channel", "rooms"],
    queryFn: async () => {
      const response = await api.get("/api/v1/ws/rooms");
      return response.data;
    },
    retry: false,
    enabled: isChannel,
  });

  const channelName = roomId
    ? channelsData?.rooms?.find((r) => r.id === roomId)?.name
    : null;

  const title = isRepo
    ? segments[2]
    : isChannel
      ? channelName
        ? `#${channelName}`
        : `#${segments[2]}`
      : location.pathname.includes("/issues")
        ? "Issues"
        : location.pathname.includes("/settings")
          ? "Settings"
          : "Repos";

  const repoName = isRepo ? segments[2] : null;

  return (
    <header className="flex h-[44px] shrink-0 items-center justify-between border-b border-border bg-background px-5">
      <div className="flex min-w-0 items-center gap-1.5 text-[13px]">
        <Link
          className="shrink-0 text-muted-foreground/40 transition-colors hover:text-foreground"
          to="/"
        >
          <Home className="size-[16px]" />
        </Link>
        <span className="shrink-0 text-muted-foreground/15">/</span>
        <Link
          className="shrink-0 truncate text-muted-foreground/50 transition-colors hover:text-foreground"
          to={`/${projectName}/repos`}
        >
          {projectName}
        </Link>
        {repoName && (
          <>
            <span className="shrink-0 text-muted-foreground/15">/</span>
            <span className="shrink-0 truncate text-muted-foreground/40">
              {repoName}
            </span>
          </>
        )}
        <span className="shrink-0 text-muted-foreground/15">/</span>
        <span className="shrink-0 font-semibold text-foreground">
          {title}
        </span>
      </div>

      <div className="flex items-center gap-1 text-muted-foreground/30">
        <CommandPalette />
        <button
          aria-label="Open search panel"
          className={cn(
            "grid size-10 place-items-center rounded-xl transition-[background-color,color] duration-150 hover:bg-accent/50 hover:text-muted-foreground/70",
            panel.showSearch && "bg-accent/50 text-foreground",
          )}
          onClick={panel.toggleSearch}
          title="Search"
          type="button"
        >
          <Search className="size-[14px]" />
        </button>
        <button
          aria-label="Open members panel"
          className={cn(
            "grid size-10 place-items-center rounded-xl transition-[background-color,color] duration-150 hover:bg-accent/50 hover:text-muted-foreground/70",
            panel.showMembers && "bg-accent/50 text-foreground",
          )}
          onClick={panel.toggleMembers}
          title="Members"
          type="button"
        >
          <Users className="size-[14px]" />
        </button>
        <button
          aria-label="Open notifications"
          className="grid size-10 place-items-center rounded-xl transition-[background-color,color] duration-150 hover:bg-accent/50 hover:text-muted-foreground/70"
          title="Notifications"
          type="button"
        >
          <Bell className="size-[14px]" />
        </button>
      </div>
    </header>
  );
}

/* ------------------------------------------------------------------ */
/*  MembersPanel                                                       */
/* ------------------------------------------------------------------ */

function MembersPanel() {
  const panel = usePanelContext();

  return (
    <div
      className={cn(
        "absolute inset-y-0 right-0 z-40 w-72 border-l border-border/30 bg-card shadow-2xl transition-transform duration-300 ease-out",
        panel.showMembers ? "translate-x-0" : "translate-x-full",
      )}
    >
      <div className="flex h-full flex-col">
        <div className="flex h-[52px] shrink-0 items-center justify-between border-b border-border/40 px-4">
          <div className="flex items-center gap-2">
            <Users className="size-4 text-primary/60" />
            <span className="text-sm font-semibold text-foreground">
              Members
            </span>
          </div>
          <Button
            aria-label="Close members panel"
            className="size-8 text-muted-foreground/40 hover:bg-accent/50 hover:text-foreground"
            onClick={panel.closeMembers}
            size="icon"
            variant="ghost"
          >
            <X className="size-4" />
          </Button>
        </div>
        <div className="min-h-0 flex-1 overflow-y-auto overscroll-contain px-3 py-2">
          {panel.membersLoading && (
            <div className="flex items-center gap-2 px-2 py-3">
              <div className="size-4 animate-spin rounded-full border-2 border-muted-foreground/20 border-t-muted-foreground/50" />
              <span className="text-xs text-muted-foreground/40">
                Loading members…
              </span>
            </div>
          )}
          {!panel.membersLoading && panel.members.length === 0 && (
            <p className="px-2 py-3 text-xs text-muted-foreground/35">
              No members yet
            </p>
          )}
          <div className="space-y-[1px]">
            {panel.members.map((member) => (
              <div
                className="flex items-center gap-2.5 rounded-xl px-3 py-2 transition-colors hover:bg-accent/[0.04]"
                key={member.id}
              >
                <span className="grid size-8 place-items-center rounded-full bg-gradient-to-br from-muted-foreground/10 to-muted-foreground/5 text-xs font-semibold text-muted-foreground/60">
                  {member.display_name?.[0]?.toUpperCase() ||
                    member.username[0]?.toUpperCase()}
                </span>
                <span className="min-w-0 flex-1 truncate text-sm text-foreground">
                  {member.display_name || member.username}
                </span>
              </div>
            ))}
          </div>
        </div>
      </div>
    </div>
  );
}

/* ------------------------------------------------------------------ */
/*  Shell                                                              */
/* ------------------------------------------------------------------ */

export function WorkspaceShell() {
  const [searchParams] = useSearchParams();
  const isEmbed = searchParams.get("embed") === "1";
  const [showMembers, setShowMembers] = useState(false);
  const [showSearch, setShowSearch] = useState(false);

  const { data: channelsData } = useQuery<{
    rooms: ChannelItem[];
    categories: CategoryItem[];
    workspace_id?: string;
  }>({
    queryKey: ["channel", "rooms"],
    queryFn: async () => {
      const response = await api.get("/api/v1/ws/rooms");
      return response.data;
    },
    retry: false,
  });
  const workspaceId =
    channelsData?.rooms[0]?.workspace_id ??
    channelsData?.workspace_id ??
    "";

  const { data: members = [], isLoading: membersLoading } = useQuery<
    WorkspaceMember[]
  >({
    queryKey: ["workspace", "members", workspaceId],
    queryFn: async () => {
      const res = await api.get<WorkspaceMember[]>(
        `/api/v1/ws/workspaces/${workspaceId}/members`,
      );
      return res.data;
    },
    enabled: Boolean(workspaceId),
    retry: false,
    staleTime: 30000,
  });

  const panelCtx = useMemo<PanelContextValue>(
    () => ({
      showMembers,
      toggleMembers: () => setShowMembers((v) => !v),
      closeMembers: () => setShowMembers(false),
      showSearch,
      toggleSearch: () => setShowSearch((v) => !v),
      closeSearch: () => setShowSearch(false),
      members,
      membersLoading,
    }),
    [showMembers, showSearch, members, membersLoading],
  );

  // Embed mode: render only the page content, no shell chrome
  if (isEmbed) {
    return (
      <div className="flex h-full flex-col overflow-hidden bg-background">
        <Outlet />
      </div>
    );
  }

  return (
    <NavShell>
      <TooltipProvider delay={300}>
        <PanelContext.Provider value={panelCtx}>
          <div className="relative flex h-full min-w-0 overflow-hidden">
            <WorkspaceSidebar />
            <main className="flex min-w-0 flex-1 flex-col overflow-hidden bg-background">
              <TopBar />
              <div className="min-h-0 flex-1 overflow-y-auto overscroll-contain">
                <Outlet />
              </div>
            </main>
            <MembersPanel />
          </div>
        </PanelContext.Provider>
      </TooltipProvider>
    </NavShell>
  );
}
