"use client";

import { useState, useEffect, Suspense, createContext, useContext } from "react";
import { usePathname, useSearchParams } from "next/navigation";
import Link from "next/link";
import {
  BellIcon,
  CircleIcon,
  LayoutGridIcon,
  UserIcon,
  UsersIcon,
  InboxIcon,
  ClockIcon,
  SettingsIcon,
  PanelLeftCloseIcon,
  PanelLeftIcon,
  CommandIcon,
} from "lucide-react";
import { getTickets, getQueues, getViews, getDashboards, getUsers, getTeams, createDashboard, getUnreadCount, getNotifications, markNotificationRead, markAllNotificationsRead, getApiTokens, createApiToken, revokeApiToken } from "@/lib/api";
import type { Dashboard, Queue, SavedView, Team, User, Notification, ApiToken } from "@/lib/types";
import { CommandPalette } from "@/components/command-palette";
import { ThemeToggle } from "@/components/theme-toggle";
import { useAuth } from "@/lib/auth-context";
import { cn, formatTicketId } from "@/lib/utils";

const SidebarCollapsedContext = createContext(false);

function useSidebarCollapsed() {
  return useContext(SidebarCollapsedContext);
}

interface ViewCounts {
  all: number;
  my: number;
  unassigned: number;
  recent: number;
}

function SidebarNavItem({
  href,
  icon: Icon,
  label,
  count,
  active,
}: {
  href: string;
  icon: React.ComponentType<{ className?: string }>;
  label: string;
  count?: number;
  active: boolean;
}) {
  const collapsed = useSidebarCollapsed();

  return (
    <Link
      href={href}
      title={collapsed ? label : undefined}
      className={cn(
        "group flex items-center px-2.5 py-1.5 rounded-md text-[13px] transition-colors",
        collapsed ? "justify-center w-full" : "justify-between",
        active
          ? "bg-sidebar-accent text-sidebar-foreground font-medium"
          : "text-sidebar-foreground/55 hover:text-sidebar-foreground hover:bg-sidebar-accent/50 font-normal"
      )}
    >
      <span className={cn("flex items-center min-w-0", collapsed ? "" : "gap-2.5")}>
        <Icon className={cn("w-4 h-4 flex-shrink-0", active ? "opacity-90" : "opacity-50 group-hover:opacity-70")} />
        {!collapsed && <span className="truncate">{label}</span>}
      </span>
      {!collapsed && count !== undefined && count > 0 && (
        <span className="min-w-5 rounded px-1 text-right text-[11px] tabular-nums text-sidebar-foreground/35">
          {count}
        </span>
      )}
    </Link>
  );
}

function SidebarNav() {
  const pathname = usePathname();
  const searchParams = useSearchParams();
  const { user: authUser } = useAuth();

  const [counts, setCounts] = useState<ViewCounts>({
    all: 0,
    my: 0,
    unassigned: 0,
    recent: 0,
  });
  const [queues, setQueues] = useState<(Queue & { count: number })[]>([]);
  const [savedViews, setSavedViews] = useState<SavedView[]>([]);
  const [dashboards, setDashboards] = useState<Dashboard[]>([]);
  const [myTeamId, setMyTeamId] = useState<string | null>(null);
  const [newDashboardName, setNewDashboardName] = useState("");
  const [addingDashboard, setAddingDashboard] = useState(false);

  const currentUserId = authUser?.id ?? null;

  useEffect(() => {
    async function load() {
      const myId = currentUserId;
      const [ticketRes, userRes] = await Promise.all([getTickets(), getUsers()]);
      const data = ticketRes.data;

      if (data) {
        const now = Date.now();
        const week = 7 * 24 * 60 * 60 * 1000;
        setCounts({
          all: data.length,
          my: myId ? data.filter((t) => t.owner_id === myId).length : 0,
          unassigned: data.filter((t) => !t.owner_id).length,
          recent: data.filter((t) => new Date(t.updated_at).getTime() > now - week).length,
        });
      }

      // Queues
      const queueRes = await getQueues();
      if (queueRes.data) {
        const qs = await Promise.all(
          queueRes.data.map((q) =>
            getTickets({ queue_id: q.id }).then(({ data: tickets }) => ({
              ...q,
              count: tickets?.length ?? 0,
            }))
          )
        );
        setQueues(qs);
      }

      // Views
      const viewRes = await getViews();
      if (viewRes.data) setSavedViews(viewRes.data);

      // Dashboards scoped to user's teams
      const [dashRes, teamRes] = await Promise.all([getDashboards(), getTeams()]);
      const allDashboards = dashRes.data ?? [];
      const allTeams = teamRes.data ?? [];
      const userTeams = myId
        ? allTeams.filter((t) => (t.members ?? []).some((m) => m.id === myId))
        : [];
      setMyTeamId(userTeams[0]?.id ?? null);
      const teamIds = new Set(userTeams.map((t) => t.id));
      const visible = allDashboards.filter((d) =>
        !d.team_id || teamIds.has(d.team_id)
      );
      setDashboards(visible);
    }
    void load();
  }, [currentUserId]);

  const collapsed = useSidebarCollapsed();

  const views = [
    {
      label: "All tickets",
      href: "/?view=all",
      param: "all",
      count: counts.all,
      icon: LayoutGridIcon,
    },
    {
      label: "My tickets",
      href: currentUserId ? `/?view=my&owner=${currentUserId}` : "/?view=my",
      param: "my",
      count: counts.my,
      icon: UserIcon,
    },
    ...(myTeamId ? [{
      label: "My team's tickets",
      href: `/?view=team&team_id=${myTeamId}`,
      param: "team",
      count: undefined as number | undefined,
      icon: UsersIcon,
    }] : []),
    {
      label: "Unassigned",
      href: "/?view=unassigned",
      param: "unassigned",
      count: counts.unassigned,
      icon: InboxIcon,
    },
    {
      label: "Recently updated",
      href: "/?view=recent",
      param: "recent",
      count: counts.recent,
      icon: ClockIcon,
    },
  ];

  const currentView = searchParams.get("view");

  return (
    <>
      <div className="mb-4">
        {views.map((view) => {
          const active =
            pathname === "/" &&
            (view.param ? currentView === view.param : !currentView);
          return (
            <SidebarNavItem
              key={view.label}
              href={view.href}
              icon={view.icon}
              label={view.label}
              count={view.count}
              active={active}
            />
          );
        })}
      </div>

      {dashboards.length > 0 && (
        <div className="mt-5">
          {!collapsed && (
            <div className="px-2.5 mb-1 text-[10px] font-medium text-sidebar-foreground/30 uppercase tracking-wider">
              Dashboards
            </div>
          )}
          {dashboards.length > 0 && (
            <div className="px-2.5">
              <select
                value={dashboards.find((d) => pathname.startsWith("/dashboards/") && pathname.endsWith(d.id))?.id ?? ""}
                onChange={(e) => {
                  const id = e.target.value;
                  if (id === "_new") {
                    setAddingDashboard(true);
                    e.target.value = dashboards.find((d) => pathname.startsWith("/dashboards/") && pathname.endsWith(d.id))?.id ?? "";
                    return;
                  }
                  if (id) window.location.href = `/dashboards/${id}`;
                }}
                className="h-7 w-full rounded border border-sidebar-border bg-sidebar-accent px-1.5 text-[12px] text-sidebar-foreground outline-none"
              >
                {dashboards.map((dash) => (
                  <option key={dash.id} value={dash.id}>{dash.name}</option>
                ))}
                <option value="_new">+ New dashboard</option>
              </select>
            </div>
          )}
          {addingDashboard && (
            <div className="mt-1 px-2">
              <input
                value={newDashboardName}
                onChange={(e) => setNewDashboardName(e.target.value)}
                placeholder="Dashboard name"
                className="h-7 w-full rounded border border-sidebar-border bg-sidebar-accent px-1.5 text-[12px] text-sidebar-foreground outline-none"
                autoFocus
                onKeyDown={async (e) => {
                  if (e.key === "Enter" && newDashboardName.trim()) {
                    const { data } = await createDashboard({ name: newDashboardName.trim(), is_default: false });
                    if (data) {
                      setDashboards((prev) => [...prev, data]);
                      setNewDashboardName("");
                      setAddingDashboard(false);
                      window.location.href = `/dashboards/${data.id}`;
                    }
                  } else if (e.key === "Escape") {
                    setNewDashboardName("");
                    setAddingDashboard(false);
                  }
                }}
                onBlur={() => {
                  if (!newDashboardName.trim()) {
                    setNewDashboardName("");
                    setAddingDashboard(false);
                  }
                }}
              />
            </div>
          )}
        </div>
      )}

      {savedViews.length > 0 && (
        <div className="mt-5">
          {!collapsed && (
            <div className="px-2.5 mb-1 text-[10px] font-medium text-sidebar-foreground/30 uppercase tracking-wider">
              Saved views
            </div>
          )}
          {savedViews.map((view) => {
            const active =
              pathname === "/" && searchParams.get("view_id") === view.id;
            return (
              <SidebarNavItem
                key={view.id}
                href={`/?view_id=${view.id}`}
                icon={ClockIcon}
                label={view.name}
                active={active}
              />
            );
          })}
        </div>
      )}

      {queues.length > 0 && (
        <div className="mt-5">
          {!collapsed && (
            <div className="px-2.5 mb-1 text-[10px] font-medium text-sidebar-foreground/30 uppercase tracking-wider">
              Queues
            </div>
          )}
          {queues.map((queue) => {
            const active =
              pathname === "/" && searchParams.get("queue") === queue.id;
            return (
              <SidebarNavItem
                key={queue.id}
                href={`/?queue=${queue.id}`}
                icon={CircleIcon}
                label={queue.name}
                count={queue.count}
                active={active}
              />
            );
          })}
        </div>
      )}
    </>
  );
}

function SidebarBottom() {
  const pathname = usePathname();
  const collapsed = useSidebarCollapsed();
  const { user, logout, isAdmin } = useAuth();
  const [tokenOpen, setTokenOpen] = useState(false);
  const [tokens, setTokens] = useState<ApiToken[]>([]);
  const [newTokenName, setNewTokenName] = useState("");
  const [newTokenValue, setNewTokenValue] = useState<string | null>(null);
  const [tokenError, setTokenError] = useState<string | null>(null);

  const loadTokens = async () => {
    const { data } = await getApiTokens();
    if (data) setTokens(data);
  };

  useEffect(() => { if (tokenOpen) { void loadTokens(); } }, [tokenOpen]);

  const handleCreateToken = async () => {
    if (!newTokenName.trim()) return;
    setTokenError(null);
    const { data, error } = await createApiToken(newTokenName.trim());
    if (error) { setTokenError(error); return; }
    if (data) {
      setNewTokenValue(data.token);
      setNewTokenName("");
      await loadTokens();
    }
  };

  const handleRevoke = async (id: string) => {
    await revokeApiToken(id);
    await loadTokens();
  };

  return (
    <div className="border-t border-sidebar-border/50 p-2 space-y-1">
      {isAdmin && (
        <SidebarNavItem
          href="/admin"
          icon={SettingsIcon}
          label="Admin"
          active={pathname === "/admin"}
        />
      )}
      {user ? (
        <>
          {!collapsed && (
            <div className="px-2.5 py-1 text-[11px] text-sidebar-foreground/50 truncate">
              {user.username}
              {isAdmin && <span className="ml-1 text-[10px] text-sidebar-foreground/30">(admin)</span>}
            </div>
          )}
          <button
            onClick={() => setTokenOpen(true)}
            className={cn(
              "w-full flex items-center px-2.5 py-1.5 rounded-md text-[13px] transition-colors",
              "text-sidebar-foreground/55 hover:text-sidebar-foreground hover:bg-sidebar-accent/50",
              collapsed ? "justify-center" : ""
            )}
          >
            <span className="opacity-50">API tokens</span>
          </button>
          <button
            onClick={logout}
            className={cn(
              "w-full flex items-center px-2.5 py-1.5 rounded-md text-[13px] transition-colors",
              "text-sidebar-foreground/55 hover:text-sidebar-foreground hover:bg-sidebar-accent/50",
              collapsed ? "justify-center" : ""
            )}
          >
            <span className="opacity-50">Sign out</span>
          </button>

          {/* Token dialog */}
          {tokenOpen && (
            <>
              <div className="fixed inset-0 z-50 bg-black/50" onClick={() => { setTokenOpen(false); setNewTokenValue(null); }} />
              <div className="fixed left-1/2 top-1/2 z-50 w-full max-w-md -translate-x-1/2 -translate-y-1/2 rounded-lg border border-border bg-popover shadow-xl">
                <div className="border-b border-border/50 px-4 py-3">
                  <h3 className="text-sm font-semibold text-foreground">API tokens</h3>
                </div>
                <div className="p-4 space-y-3">
                  {newTokenValue ? (
                    <div className="rounded-md border border-amber-500/30 bg-amber-500/10 p-3">
                      <p className="text-xs font-semibold text-foreground">Token created — copy it now:</p>
                      <pre className="mt-1.5 select-all rounded bg-background px-2 py-1.5 font-mono text-xs break-all">{newTokenValue}</pre>
                      <p className="mt-1 text-[10px] text-muted-foreground">This won't be shown again.</p>
                    </div>
                  ) : (
                    <div className="flex items-center gap-1.5">
                      <input
                        value={newTokenName}
                        onChange={(e) => setNewTokenName(e.target.value)}
                        placeholder="Token name..."
                        className="h-7 flex-1 rounded-md border border-input bg-transparent px-2 text-xs outline-none focus:border-ring"
                        onKeyDown={(e) => { if (e.key === 'Enter') handleCreateToken(); }}
                      />
                      <button
                        onClick={handleCreateToken}
                        disabled={!newTokenName.trim()}
                        className="h-7 rounded-md bg-primary px-2.5 text-[11px] font-semibold text-primary-foreground hover:bg-primary/90 disabled:bg-muted disabled:text-muted-foreground"
                      >
                        Create
                      </button>
                    </div>
                  )}
                  {tokenError && <p className="text-xs text-destructive">{tokenError}</p>}
                  {tokens.length > 0 ? (
                    <div className="space-y-1">
                      {tokens.map((t) => (
                        <div key={t.id} className="flex items-center justify-between rounded-md border border-border/30 px-2.5 py-1.5">
                          <div>
                            <p className="text-xs font-medium">{t.name}</p>
                            <p className="text-[10px] text-muted-foreground">
                              Created {new Date(t.created_at).toLocaleDateString()}
                              {t.last_used_at && ` · Last used ${new Date(t.last_used_at).toLocaleDateString()}`}
                            </p>
                          </div>
                          <button
                            onClick={() => handleRevoke(t.id)}
                            className="text-[10px] text-muted-foreground hover:text-destructive"
                          >
                            Revoke
                          </button>
                        </div>
                      ))}
                    </div>
                  ) : (
                    <p className="text-xs text-muted-foreground">No API tokens yet.</p>
                  )}
                </div>
              </div>
            </>
          )}
        </>
      ) : (
        <SidebarNavItem
          href="/login"
          icon={UserIcon}
          label="Sign in"
          active={pathname === "/login"}
        />
      )}
      <div className={cn("flex", collapsed ? "justify-center" : "px-1")}>
        <ThemeToggle />
      </div>
    </div>
  );
}

function NotificationBell({ collapsed, setCommandOpen }: { collapsed: boolean; setCommandOpen: (v: boolean) => void }) {
  const [unread, setUnread] = useState(0);
  const [notifs, setNotifs] = useState<Notification[]>([]);
  const [open, setOpen] = useState(false);
  const { user } = useAuth();

  useEffect(() => {
    if (!user) return;
    const load = async () => {
      const [countRes, notifRes] = await Promise.all([getUnreadCount(), getNotifications()]);
      if (countRes.data) setUnread(countRes.data.count);
      if (notifRes.data) setNotifs(notifRes.data);
    };
    void load();
    // Poll every 30s
    const interval = setInterval(() => { void load(); }, 30000);
    return () => clearInterval(interval);
  }, [user]);

  if (!user) return null;

  const handleMarkRead = async (id: string) => {
    await markNotificationRead(id);
    setUnread((c) => Math.max(0, c - 1));
    setNotifs((prev) => prev.map((n) => n.id === id ? { ...n, read: true } : n));
  };

  const handleMarkAll = async () => {
    await markAllNotificationsRead();
    setUnread(0);
    setNotifs((prev) => prev.map((n) => ({ ...n, read: true })));
  };

  return (
    <div className="relative">
      <button
        onClick={() => setOpen(!open)}
        className="relative flex h-7 w-7 items-center justify-center rounded text-sidebar-foreground/55 hover:text-sidebar-foreground hover:bg-sidebar-accent/50 transition-colors"
      >
        <BellIcon className="h-4 w-4" />
        {unread > 0 && (
          <span className="absolute -top-0.5 -right-0.5 flex h-4 min-w-4 items-center justify-center rounded-full bg-destructive px-1 text-[9px] font-bold text-destructive-foreground">
            {unread > 99 ? '99+' : unread}
          </span>
        )}
      </button>

      {open && (
        <>
          <div className="fixed inset-0 z-30" onClick={() => setOpen(false)} />
          <div className="absolute right-0 top-full z-40 mt-1 w-80 rounded-lg border border-border bg-popover shadow-lg">
            <div className="flex items-center justify-between border-b border-border/50 px-3 py-2">
              <span className="text-xs font-semibold text-foreground">Notifications</span>
              {unread > 0 && (
                <button onClick={handleMarkAll} className="text-[10px] text-muted-foreground hover:text-foreground">
                  Mark all read
                </button>
              )}
            </div>
            <div className="max-h-80 overflow-auto">
              {notifs.length === 0 ? (
                <div className="px-3 py-6 text-center text-xs text-muted-foreground">
                  No notifications yet.
                </div>
              ) : (
                notifs.slice(0, 20).map((n) => (
                  <button
                    key={n.id}
                    onClick={() => {
                      handleMarkRead(n.id);
                      if (n.ticket_id) window.location.href = `/tickets/${n.ticket_id}`;
                    }}
                    className={cn(
                      "w-full border-b border-border/30 px-3 py-2.5 text-left transition-colors hover:bg-accent/30",
                      !n.read && "bg-primary/5"
                    )}
                  >
                    <div className="flex items-start gap-2">
                      <div className={cn(
                        "mt-0.5 h-2 w-2 shrink-0 rounded-full",
                        n.read ? "bg-border" : "bg-primary"
                      )} />
                      <div className="min-w-0">
                        <p className="text-xs font-medium text-foreground">{n.title}</p>
                        {n.body && (
                          <p className="mt-0.5 truncate text-[11px] text-muted-foreground">{n.body}</p>
                        )}
                        {n.ticket_id && (
                          <p className="mt-0.5 text-[10px] text-muted-foreground/60">
                            {formatTicketId(n.ticket_id)}
                          </p>
                        )}
                      </div>
                    </div>
                  </button>
                ))
              )}
            </div>
          </div>
        </>
      )}

      {!collapsed && (
        <button
          onClick={() => setCommandOpen(true)}
          className="flex h-6 items-center gap-1 rounded border border-sidebar-border/50 px-1.5 text-[10px] text-sidebar-foreground/40 transition-colors hover:bg-sidebar-accent hover:text-sidebar-foreground/60"
          aria-label="Open command palette"
        >
          <CommandIcon className="h-3 w-3" />K
        </button>
      )}
    </div>
  );
}

export function AppShell({ children }: { children: React.ReactNode }) {
  const [commandOpen, setCommandOpen] = useState(false);
  const [sidebarCollapsed, setSidebarCollapsed] = useState(false);

  useEffect(() => {
    const down = (e: KeyboardEvent) => {
      if ((e.key === "k" && (e.metaKey || e.ctrlKey)) || e.key === "/") {
        if (
          e.target instanceof HTMLInputElement ||
          e.target instanceof HTMLTextAreaElement ||
          (e.target instanceof HTMLElement && e.target.isContentEditable)
        ) {
          return;
        }
        e.preventDefault();
        setCommandOpen((o) => !o);
      }
    };
    document.addEventListener("keydown", down);
    return () => document.removeEventListener("keydown", down);
  }, []);

  return (
    <SidebarCollapsedContext.Provider value={sidebarCollapsed}>
      <div className="flex h-screen overflow-hidden bg-background">
        {/* Sidebar */}
        <aside
          className={cn(
            "flex-shrink-0 flex flex-col bg-sidebar border-r border-sidebar-border/50 transition-all duration-200",
            sidebarCollapsed ? "w-[56px]" : "w-[232px]"
          )}
        >
          {/* Brand */}
          <div className="h-12 flex items-center justify-between gap-2 px-3 border-b border-sidebar-border/50">
            <Link href="/" className="flex items-center gap-2.5">
              <div className="w-6 h-6 rounded-md bg-sidebar-primary flex items-center justify-center">
                <span className="text-sidebar-primary-foreground text-[11px] font-bold">T</span>
              </div>
              {!sidebarCollapsed && (
                <span className="text-sm font-semibold text-sidebar-foreground tracking-tight">Tessera</span>
              )}
            </Link>
            <NotificationBell collapsed={sidebarCollapsed} setCommandOpen={setCommandOpen} />
          </div>

          {/* Nav */}
          <nav className="flex-1 overflow-y-auto py-2.5 px-2">
            <Suspense
              fallback={
                <div className="space-y-1.5 px-2">
                  {Array.from({ length: 6 }).map((_, i) => (
                    <div
                      key={i}
                    className="h-7 bg-sidebar-accent rounded-md animate-pulse"
                    />
                  ))}
                </div>
              }
            >
              <SidebarNav />
            </Suspense>
          </nav>

          {/* Bottom */}
          <SidebarBottom />
        </aside>

        {/* Main */}
        <main className="flex-1 overflow-hidden bg-background/88">{children}</main>

        {/* Command Palette */}
        <CommandPalette open={commandOpen} onOpenChange={setCommandOpen} />
      </div>

      {/* Collapse toggle */}
      <button
        onClick={() => setSidebarCollapsed(!sidebarCollapsed)}
        className="fixed bottom-4 left-0 z-40 w-6 h-6 flex items-center justify-center rounded-r-md bg-sidebar border border-sidebar-border border-l-0 text-sidebar-foreground/55 hover:text-sidebar-foreground transition-all duration-150"
        style={{ left: sidebarCollapsed ? 60 : 240 }}
        aria-label={sidebarCollapsed ? "Expand sidebar" : "Collapse sidebar"}
      >
        {sidebarCollapsed ? (
          <PanelLeftIcon className="w-3.5 h-3.5" />
        ) : (
          <PanelLeftCloseIcon className="w-3.5 h-3.5" />
        )}
      </button>
    </SidebarCollapsedContext.Provider>
  );
}
