import { useEffect, useMemo, useState } from "react";
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
import {
  Download,
  Search,
  TrendingUp,
} from "lucide-react";
import { useCompany } from "@/context/CompanyContext";
import { useBreadcrumbs } from "@/context/BreadcrumbContext";
import { useToast } from "@/context/ToastContext";
import { skillRegistryApi } from "@/api/skillRegistry";
import { skillGroupsApi } from "@/api/skillGroups";
import { agentsApi } from "@/api/agents";
import { queryKeys } from "@/lib/queryKeys";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from "@/components/ui/select";
import { Tabs, TabsContent } from "@/components/ui/tabs";
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogTitle,
} from "@/components/ui/dialog";
import { SkillCard } from "@/components/SkillCard";
import { EmptyState } from "@/components/EmptyState";
import { FilterBar } from "@/components/FilterBar";
import type { FilterValue } from "@/components/FilterBar";
import { PageTabBar } from "@/components/PageTabBar";
import { PageSkeleton } from "@/components/PageSkeleton";
import { Identity } from "@/components/Identity";
import { cn } from "@/lib/utils";
import { getUIAdapter } from "@/adapters";
import { resolveAdapterSkillConfig, listAdapterSkillConfigs } from "@paperclipai/adapter-utils";

// Compute compatible adapter labels once at module level (used by Browse/Trending SkillCards)
const COMPATIBLE_ADAPTER_LABELS = listAdapterSkillConfigs()
  .filter((c) => c.supportsInstall)
  .map((c) => getUIAdapter(c.adapterType).label);

type SortBy = "rating" | "name" | "recent";

export function SkillBrowser() {
  const { selectedCompany } = useCompany();
  const { setBreadcrumbs } = useBreadcrumbs();
  const queryClient = useQueryClient();
  const { pushToast } = useToast();

  // Tab state
  const [tab, setTab] = useState<"browse" | "installed" | "trending">("browse");

  // Browse tab filter state
  const [search, setSearch] = useState("");
  const [sourceFilter, setSourceFilter] = useState<string | null>(null);
  const [categoryFilter, setCategoryFilter] = useState<string | null>(null);
  const [sortBy, setSortBy] = useState<SortBy>("rating");

  // Installed tab: selected agent for per-agent skill view
  const [selectedAgentId, setSelectedAgentId] = useState<string | null>(null);

  // Dialog state
  const [installDialog, setInstallDialog] = useState<{ skillId: string; isUpdate?: boolean } | null>(null);
  const [uninstallDialog, setUninstallDialog] = useState<{ skillId: string; agentId: string } | null>(null);
  const [unsupportedMessage, setUnsupportedMessage] = useState<string | null>(null);

  useEffect(() => {
    setBreadcrumbs([
      { label: selectedCompany?.name ?? "Workspace", href: "/dashboard" },
      { label: "Skills" },
    ]);
  }, [selectedCompany?.name, setBreadcrumbs]);

  // Data fetching
  const { data: skills = [], isLoading, isError } = useQuery({
    queryKey: queryKeys.skillRegistry.list,
    queryFn: () => skillRegistryApi.list(),
  });

  const { data: agents = [] } = useQuery({
    queryKey: queryKeys.agents.list(selectedCompany?.id ?? ""),
    queryFn: () => agentsApi.list(selectedCompany?.id ?? ""),
    enabled: !!selectedCompany?.id,
  });

  // Per-agent installed skills (for Installed tab)
  const { data: agentInstalledSkills = [] } = useQuery({
    queryKey: ["agentInstalledSkills", selectedAgentId],
    queryFn: () => skillGroupsApi.listAgentSkills(selectedAgentId!),
    enabled: tab === "installed" && !!selectedAgentId,
  });

  // Mutations
  const fetchMutation = useMutation({
    mutationFn: () => skillRegistryApi.fetch(),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: queryKeys.skillRegistry.list });
      pushToast({ title: "Registry refreshed", tone: "success" });
    },
    onError: (err: Error) => {
      pushToast({ title: "Registry refresh failed", body: err.message, tone: "error" });
    },
  });

  const installMutation = useMutation({
    mutationFn: (params: { skillId: string; agentId: string }) =>
      skillRegistryApi.install(params.skillId, params.agentId),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: queryKeys.skillRegistry.list });
      if (selectedAgentId) {
        queryClient.invalidateQueries({ queryKey: ["agentInstalledSkills", selectedAgentId] });
      }
      pushToast({ title: "Skill installed", tone: "success" });
    },
    onError: (err: Error) => {
      pushToast({ title: "Install failed", body: err.message, tone: "error" });
    },
  });

  const updateMutation = useMutation({
    mutationFn: (params: { skillId: string; agentId: string }) =>
      skillRegistryApi.install(params.skillId, params.agentId),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: queryKeys.skillRegistry.list });
      if (selectedAgentId) {
        queryClient.invalidateQueries({ queryKey: ["agentInstalledSkills", selectedAgentId] });
      }
      pushToast({ title: "Skill updated", tone: "success" });
    },
    onError: (err: Error) => {
      pushToast({ title: "Update failed", body: err.message, tone: "error" });
    },
  });

  const rollbackMutation = useMutation({
    mutationFn: (params: { skillId: string; versionId: string; agentId: string }) =>
      skillRegistryApi.rollback(params.skillId, params.versionId, params.agentId),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: queryKeys.skillRegistry.list });
      pushToast({ title: "Rolled back to previous version", tone: "success" });
    },
    onError: (err: Error) => {
      pushToast({ title: "Rollback failed", body: err.message, tone: "error" });
    },
  });

  const removeMutation = useMutation({
    mutationFn: (params: { skillId: string; agentId: string }) =>
      skillRegistryApi.uninstall(params.skillId, params.agentId),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: queryKeys.skillRegistry.list });
      if (selectedAgentId) {
        queryClient.invalidateQueries({ queryKey: ["agentInstalledSkills", selectedAgentId] });
      }
      pushToast({ title: "Skill uninstalled", tone: "success" });
    },
  });

  // Derived data for filters
  const sources = useMemo(
    () => [...new Set(skills.map((s) => s.sourceId))].sort(),
    [skills],
  );
  const categories = useMemo(
    () => [...new Set(skills.map((s) => s.category).filter(Boolean) as string[])].sort(),
    [skills],
  );

  // Browse tab filtering
  const filteredSkills = useMemo(() => {
    let result = skills.filter((s) => !s.removedAt);
    if (search) {
      result = result.filter(
        (s) =>
          s.name.toLowerCase().includes(search.toLowerCase()) ||
          s.description?.toLowerCase().includes(search.toLowerCase()),
      );
    }
    if (sourceFilter) result = result.filter((s) => s.sourceId === sourceFilter);
    if (categoryFilter) result = result.filter((s) => s.category === categoryFilter);
    result = [...result];
    if (sortBy === "rating") result.sort((a, b) => (b.averageRating ?? 0) - (a.averageRating ?? 0));
    else if (sortBy === "name") result.sort((a, b) => a.name.localeCompare(b.name));
    return result;
  }, [skills, search, sourceFilter, categoryFilter, sortBy]);

  // Active filter chips
  const activeFilters = useMemo(() => {
    const filters: FilterValue[] = [];
    if (sourceFilter) filters.push({ key: "source", label: "Source", value: sourceFilter });
    if (categoryFilter) filters.push({ key: "category", label: "Category", value: categoryFilter });
    return filters;
  }, [sourceFilter, categoryFilter]);

  const handleClearFilters = () => {
    setSourceFilter(null);
    setCategoryFilter(null);
  };

  const handleRemoveFilter = (key: string) => {
    if (key === "source") setSourceFilter(null);
    if (key === "category") setCategoryFilter(null);
  };

  // Installed tab: split into managed/native
  const managedSkills = useMemo(
    () => agentInstalledSkills.filter((s) => s.source === "managed"),
    [agentInstalledSkills],
  );
  const nativeSkills = useMemo(
    () => agentInstalledSkills.filter((s) => s.source === "native"),
    [agentInstalledSkills],
  );

  // Helper: get SkillListItem by skillId (for rendering in Installed tab)
  const skillById = useMemo(() => {
    const map = new Map(skills.map((s) => [s.id, s]));
    return map;
  }, [skills]);

  // Trending tab sections
  const activeSkills = useMemo(() => skills.filter((s) => !s.removedAt), [skills]);

  const gainingTraction = useMemo(
    () => [...activeSkills].sort((a, b) => (b.ratingCount ?? 0) - (a.ratingCount ?? 0)).slice(0, 6),
    [activeSkills],
  );

  const recentlyUpdated = useMemo(
    () => [...activeSkills].sort((a, b) => b.id.localeCompare(a.id)).slice(0, 6),
    [activeSkills],
  );

  const youMightLike = useMemo(() => {
    const installedCategories = new Set(
      activeSkills
        .filter((s) => s.activeVersionId)
        .map((s) => s.category)
        .filter(Boolean),
    );
    if (installedCategories.size === 0)
      return activeSkills.filter((s) => !s.activeVersionId).slice(0, 6);
    return activeSkills
      .filter((s) => !s.activeVersionId && s.category && installedCategories.has(s.category))
      .slice(0, 6);
  }, [activeSkills]);

  const handleRollback = (skillId: string) => {
    // Rollback requires a versionId — without version selection UI, use a no-op for now.
    // Full rollback flow is in Plan 03 (SkillDetail page).
    pushToast({ title: "Select a version from the skill detail page to roll back.", tone: "info" });
    void skillId;
  };

  const handleInstallForAgent = (agentId: string) => {
    if (!installDialog) return;
    const agent = agents.find((a) => a.id === agentId);
    if (agent) {
      const cfg = resolveAdapterSkillConfig(agent.adapterType ?? "process");
      if (!cfg.supportsInstall) {
        setUnsupportedMessage(
          cfg.unsupportedReason ?? "This adapter does not support skill installation."
        );
        return;
      }
    }
    if (installDialog.isUpdate) {
      updateMutation.mutate({ skillId: installDialog.skillId, agentId });
    } else {
      installMutation.mutate({ skillId: installDialog.skillId, agentId });
    }
    setInstallDialog(null);
  };

  const tabItems = [
    { value: "browse", label: "Browse" },
    { value: "installed", label: "Installed" },
    { value: "trending", label: "Trending" },
  ];

  return (
    <main className="flex-1 overflow-y-auto p-6 space-y-4">
      {/* Header */}
      <div className="flex items-center justify-between">
        <h1 className="text-xl font-semibold">Skills</h1>
        <Button
          variant="outline"
          size="sm"
          onClick={() => fetchMutation.mutate()}
          disabled={fetchMutation.isPending}
        >
          {fetchMutation.isPending ? "Refreshing..." : "Refresh registry"}
        </Button>
      </div>

      {/* Error state */}
      {isError && (
        <p className="text-sm text-destructive">
          Failed to load skills. Check that the skill registry backend is running and try again.
        </p>
      )}

      {/* Loading state */}
      {isLoading && <PageSkeleton variant="list" />}

      {/* Tabs */}
      {!isLoading && (
        <Tabs value={tab} onValueChange={(v) => setTab(v as typeof tab)}>
          <PageTabBar items={tabItems} value={tab} onValueChange={(v) => setTab(v as typeof tab)} align="start" />

          {/* Browse tab */}
          <TabsContent value="browse" className="space-y-4">
            {/* Toolbar */}
            <div className="flex flex-wrap gap-2">
              <Input
                placeholder="Search skills\u2026"
                aria-label="Search skills"
                className="max-w-xs"
                value={search}
                onChange={(e) => setSearch(e.target.value)}
              />
              <Select
                value={sourceFilter ?? ""}
                onValueChange={(v) => setSourceFilter(v || null)}
              >
                <SelectTrigger className="w-36">
                  <SelectValue placeholder="All sources" />
                </SelectTrigger>
                <SelectContent>
                  {sources.map((s) => (
                    <SelectItem key={s} value={s}>
                      {s}
                    </SelectItem>
                  ))}
                </SelectContent>
              </Select>
              <Select
                value={categoryFilter ?? ""}
                onValueChange={(v) => setCategoryFilter(v || null)}
              >
                <SelectTrigger className="w-40">
                  <SelectValue placeholder="All categories" />
                </SelectTrigger>
                <SelectContent>
                  {categories.map((c) => (
                    <SelectItem key={c} value={c}>
                      {c}
                    </SelectItem>
                  ))}
                </SelectContent>
              </Select>
              <Select
                value={sortBy}
                onValueChange={(v) => setSortBy(v as SortBy)}
              >
                <SelectTrigger className="w-36">
                  <SelectValue />
                </SelectTrigger>
                <SelectContent>
                  <SelectItem value="rating">Sort: Rating</SelectItem>
                  <SelectItem value="name">Sort: Name</SelectItem>
                  <SelectItem value="recent">Sort: Recent</SelectItem>
                </SelectContent>
              </Select>
            </div>

            {/* Active filter chips */}
            <FilterBar
              filters={activeFilters}
              onRemove={handleRemoveFilter}
              onClear={handleClearFilters}
            />

            {/* Skill grid */}
            {filteredSkills.length > 0 && (
              <div className={cn("grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4")}>
                {filteredSkills.map((skill) => (
                  <SkillCard
                    key={skill.id}
                    skill={skill}
                    isInstalled={!!skill.activeVersionId}
                    hasUpdate={false}
                    compatibleAdapters={COMPATIBLE_ADAPTER_LABELS}
                    onInstall={() => setInstallDialog({ skillId: skill.id })}
                    onUpdate={() => setInstallDialog({ skillId: skill.id, isUpdate: true })}
                    onRollback={() => handleRollback(skill.id)}
                    onUninstall={() => {
                      // Browse tab uninstall: no specific agentId context — open install dialog to select agent first
                      void skill.id;
                    }}
                  />
                ))}
              </div>
            )}

            {/* Browse empty state */}
            {filteredSkills.length === 0 && (
              <EmptyState
                icon={Search}
                message="No skills found"
                action="Refresh registry"
                onAction={() => fetchMutation.mutate()}
              />
            )}
          </TabsContent>

          {/* Installed tab */}
          <TabsContent value="installed" className="space-y-6">
            {/* Agent selector for installed tab */}
            {agents.length === 0 && (
              <EmptyState
                icon={Download}
                message="No agents found in this workspace."
              />
            )}
            {agents.length > 0 && !selectedAgentId && (
              <div className="space-y-2">
                <p className="text-sm text-muted-foreground">Select an agent to view installed skills:</p>
                <div className="flex flex-wrap gap-2">
                  {agents.map((agent) => (
                    <Button
                      key={agent.id}
                      variant="outline"
                      size="sm"
                      onClick={() => setSelectedAgentId(agent.id)}
                    >
                      <Identity name={agent.name} size="sm" />
                      <span className="text-muted-foreground ml-1 text-xs">
                        ({getUIAdapter(agent.adapterType ?? "process").label})
                      </span>
                    </Button>
                  ))}
                </div>
              </div>
            )}
            {selectedAgentId && (
              <div className="space-y-4">
                {/* Back to agent selector */}
                <div className="flex items-center gap-2">
                  <Button
                    variant="ghost"
                    size="sm"
                    onClick={() => setSelectedAgentId(null)}
                    className="text-xs"
                  >
                    &larr; All agents
                  </Button>
                  <span className="text-sm font-medium">
                    {agents.find((a) => a.id === selectedAgentId)?.name ?? selectedAgentId}
                    {(() => {
                      const a = agents.find((ag) => ag.id === selectedAgentId);
                      return a ? (
                        <span className="text-muted-foreground ml-1 text-xs font-normal">
                          ({getUIAdapter(a.adapterType ?? "process").label})
                        </span>
                      ) : null;
                    })()}
                  </span>
                </div>

                {agentInstalledSkills.length === 0 && (
                  <EmptyState
                    icon={Download}
                    message="No skills installed for this agent"
                    action="Browse skills"
                    onAction={() => setTab("browse")}
                  />
                )}

                {/* Managed skills section */}
                {managedSkills.length > 0 && (
                  <>
                    {nativeSkills.length > 0 && (
                      <h3 className="text-sm font-medium text-muted-foreground mt-4 mb-2">Managed</h3>
                    )}
                    <div className={cn("grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4")}>
                      {managedSkills.map((entry) => {
                        const skill = skillById.get(entry.skillId);
                        if (!skill) return null;
                        return (
                          <SkillCard
                            key={entry.skillId}
                            skill={skill}
                            isInstalled
                            hasUpdate={false}
                            source="managed"
                            onRollback={() => handleRollback(entry.skillId)}
                            onUninstall={() => setUninstallDialog({ skillId: entry.skillId, agentId: selectedAgentId })}
                          />
                        );
                      })}
                    </div>
                  </>
                )}

                {/* Native skills section */}
                {nativeSkills.length > 0 && (
                  <>
                    <h3 className="text-sm font-medium text-muted-foreground mt-4 mb-2">Native</h3>
                    <div className={cn("grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4")}>
                      {nativeSkills.map((entry) => {
                        const skill = skillById.get(entry.skillId);
                        if (!skill) return null;
                        return (
                          <SkillCard
                            key={entry.skillId}
                            skill={skill}
                            isInstalled
                            hasUpdate={false}
                            isReadOnly={true}
                            source="native"
                          />
                        );
                      })}
                    </div>
                  </>
                )}
              </div>
            )}
          </TabsContent>

          {/* Trending tab */}
          <TabsContent value="trending" className="space-y-8">
            {skills.length === 0 && (
              <EmptyState
                icon={TrendingUp}
                message="No trending data yet"
              />
            )}
            {skills.length > 0 && (
              <>
                <section>
                  <h2 className="text-sm font-semibold text-muted-foreground uppercase tracking-wide mb-3">
                    Gaining Traction
                  </h2>
                  <div className={cn("grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4")}>
                    {gainingTraction.map((skill) => (
                      <SkillCard
                        key={skill.id}
                        skill={skill}
                        isInstalled={!!skill.activeVersionId}
                        hasUpdate={false}
                        compatibleAdapters={COMPATIBLE_ADAPTER_LABELS}
                        onInstall={() => setInstallDialog({ skillId: skill.id })}
                        onUpdate={() => setInstallDialog({ skillId: skill.id, isUpdate: true })}
                        onRollback={() => handleRollback(skill.id)}
                        onUninstall={() => void skill.id}
                      />
                    ))}
                  </div>
                </section>
                <section>
                  <h2 className="text-sm font-semibold text-muted-foreground uppercase tracking-wide mb-3">
                    Recently Updated
                  </h2>
                  <div className={cn("grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4")}>
                    {recentlyUpdated.map((skill) => (
                      <SkillCard
                        key={skill.id}
                        skill={skill}
                        isInstalled={!!skill.activeVersionId}
                        hasUpdate={false}
                        compatibleAdapters={COMPATIBLE_ADAPTER_LABELS}
                        onInstall={() => setInstallDialog({ skillId: skill.id })}
                        onUpdate={() => setInstallDialog({ skillId: skill.id, isUpdate: true })}
                        onRollback={() => handleRollback(skill.id)}
                        onUninstall={() => void skill.id}
                      />
                    ))}
                  </div>
                </section>
                <section>
                  <h2 className="text-sm font-semibold text-muted-foreground uppercase tracking-wide mb-3">
                    You Might Like
                  </h2>
                  <div className={cn("grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4")}>
                    {youMightLike.map((skill) => (
                      <SkillCard
                        key={skill.id}
                        skill={skill}
                        isInstalled={!!skill.activeVersionId}
                        hasUpdate={false}
                        compatibleAdapters={COMPATIBLE_ADAPTER_LABELS}
                        onInstall={() => setInstallDialog({ skillId: skill.id })}
                        onUpdate={() => setInstallDialog({ skillId: skill.id, isUpdate: true })}
                        onRollback={() => handleRollback(skill.id)}
                        onUninstall={() => void skill.id}
                      />
                    ))}
                  </div>
                </section>
              </>
            )}
          </TabsContent>
        </Tabs>
      )}

      {/* Agent selector dialog (install / update) */}
      <Dialog
        open={!!installDialog}
        onOpenChange={(open) => {
          if (!open) {
            setInstallDialog(null);
            setUnsupportedMessage(null);
          }
        }}
      >
        <DialogContent>
          <DialogHeader>
            <DialogTitle>Select agent</DialogTitle>
            <DialogDescription>
              Choose which agent should receive this skill.
            </DialogDescription>
          </DialogHeader>
          <div className="space-y-3">
            {unsupportedMessage && (
              <div className="rounded-md border border-destructive/50 bg-destructive/10 p-3 text-sm">
                <p className="font-medium text-destructive">Cannot install on this agent</p>
                <p className="text-muted-foreground mt-1">{unsupportedMessage}</p>
                <Button variant="ghost" size="sm" className="mt-2" onClick={() => setUnsupportedMessage(null)}>
                  Dismiss
                </Button>
              </div>
            )}
            <div className="space-y-1">
              {agents.length === 0 && (
                <p className="text-sm text-muted-foreground">No agents found in this workspace.</p>
              )}
              {agents.map((agent) => (
                <Button
                  key={agent.id}
                  variant="outline"
                  className="w-full justify-start"
                  disabled={installMutation.isPending || updateMutation.isPending}
                  onClick={() => handleInstallForAgent(agent.id)}
                >
                  <Identity name={agent.name} size="sm" />
                  <span className="text-muted-foreground ml-1 text-xs">
                    ({getUIAdapter(agent.adapterType ?? "process").label})
                  </span>
                </Button>
              ))}
            </div>
          </div>
          <DialogFooter>
            <Button
              variant="outline"
              onClick={() => {
                setInstallDialog(null);
                setUnsupportedMessage(null);
              }}
            >
              Cancel
            </Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>

      {/* Uninstall confirmation dialog */}
      <Dialog
        open={!!uninstallDialog}
        onOpenChange={(open) => !open && setUninstallDialog(null)}
      >
        <DialogContent>
          <DialogHeader>
            <DialogTitle>Uninstall skill?</DialogTitle>
            <DialogDescription>
              This will remove the skill files from the agent&apos;s directory. You can reinstall it later.
            </DialogDescription>
          </DialogHeader>
          <DialogFooter>
            <Button variant="outline" onClick={() => setUninstallDialog(null)}>
              Keep skill
            </Button>
            <Button
              variant="destructive"
              disabled={removeMutation.isPending}
              onClick={() => {
                if (uninstallDialog) {
                  removeMutation.mutate({ skillId: uninstallDialog.skillId, agentId: uninstallDialog.agentId });
                  setUninstallDialog(null);
                }
              }}
            >
              Yes, uninstall
            </Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>
    </main>
  );
}
