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 { 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";

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");

  // Dialog state
  const [installDialog, setInstallDialog] = useState<{ skillId: string; isUpdate?: boolean } | null>(null);
  const [agentSkillsDir, setAgentSkillsDir] = useState("");
  const [uninstallDialog, setUninstallDialog] = useState<{ skillId: 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,
  });

  // 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; agentSkillsDir: string }) =>
      skillRegistryApi.install(params.skillId, params.agentSkillsDir),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: queryKeys.skillRegistry.list });
      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; agentSkillsDir: string }) =>
      skillRegistryApi.install(params.skillId, params.agentSkillsDir),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: queryKeys.skillRegistry.list });
      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; agentSkillsDir: string }) =>
      skillRegistryApi.rollback(params.skillId, params.versionId, params.agentSkillsDir),
    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: (skillId: string) => skillRegistryApi.remove(skillId),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: queryKeys.skillRegistry.list });
      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 grouping
  const installedGroups = useMemo(() => {
    const installed = skills.filter((s) => s.activeVersionId && !s.removedAt);
    if (installed.length === 0) return [];
    return [{ agentId: "all", agentName: "All Agents", skills: installed }];
  }, [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 dir = agentSkillsDir.trim() || `/agents/${agentId}/.claude/skills`;
    if (installDialog.isUpdate) {
      updateMutation.mutate({ skillId: installDialog.skillId, agentSkillsDir: dir });
    } else {
      installMutation.mutate({ skillId: installDialog.skillId, agentSkillsDir: dir });
    }
    setInstallDialog(null);
    setAgentSkillsDir("");
  };

  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}
                    onInstall={() => setInstallDialog({ skillId: skill.id })}
                    onUpdate={() => setInstallDialog({ skillId: skill.id, isUpdate: true })}
                    onRollback={() => handleRollback(skill.id)}
                    onUninstall={() => setUninstallDialog({ skillId: 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">
            {installedGroups.length === 0 && (
              <EmptyState
                icon={Download}
                message="No skills installed"
                action="Browse skills"
                onAction={() => setTab("browse")}
              />
            )}
            {installedGroups.map((group) => (
              <div key={group.agentId}>
                <div className="flex items-center gap-2 px-4 py-2 bg-muted/50 rounded-t-md">
                  <Identity name={group.agentName} size="sm" />
                  <span className="text-xs text-muted-foreground ml-1">{group.skills.length}</span>
                </div>
                <div className={cn("grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4 pt-3")}>
                  {group.skills.map((skill) => (
                    <SkillCard
                      key={skill.id}
                      skill={skill}
                      isInstalled
                      hasUpdate={false}
                      onRollback={() => handleRollback(skill.id)}
                      onUninstall={() => setUninstallDialog({ skillId: skill.id })}
                    />
                  ))}
                </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}
                        onInstall={() => setInstallDialog({ skillId: skill.id })}
                        onUpdate={() => setInstallDialog({ skillId: skill.id, isUpdate: true })}
                        onRollback={() => handleRollback(skill.id)}
                        onUninstall={() => setUninstallDialog({ skillId: 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}
                        onInstall={() => setInstallDialog({ skillId: skill.id })}
                        onUpdate={() => setInstallDialog({ skillId: skill.id, isUpdate: true })}
                        onRollback={() => handleRollback(skill.id)}
                        onUninstall={() => setUninstallDialog({ skillId: 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}
                        onInstall={() => setInstallDialog({ skillId: skill.id })}
                        onUpdate={() => setInstallDialog({ skillId: skill.id, isUpdate: true })}
                        onRollback={() => handleRollback(skill.id)}
                        onUninstall={() => setUninstallDialog({ skillId: skill.id })}
                      />
                    ))}
                  </div>
                </section>
              </>
            )}
          </TabsContent>
        </Tabs>
      )}

      {/* Agent selector dialog (install / update) */}
      <Dialog
        open={!!installDialog}
        onOpenChange={(open) => {
          if (!open) {
            setInstallDialog(null);
            setAgentSkillsDir("");
          }
        }}
      >
        <DialogContent>
          <DialogHeader>
            <DialogTitle>Select agent</DialogTitle>
            <DialogDescription>
              Choose which agent should receive this skill.
            </DialogDescription>
          </DialogHeader>
          <div className="space-y-3">
            <div className="space-y-1">
              <label className="text-xs text-muted-foreground" htmlFor="skills-dir-input">
                Agent skills directory (leave blank to use default)
              </label>
              <Input
                id="skills-dir-input"
                placeholder="/path/to/agent/.claude/skills"
                value={agentSkillsDir}
                onChange={(e) => setAgentSkillsDir(e.target.value)}
              />
            </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" />
                </Button>
              ))}
            </div>
          </div>
          <DialogFooter>
            <Button
              variant="outline"
              onClick={() => {
                setInstallDialog(null);
                setAgentSkillsDir("");
              }}
            >
              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(uninstallDialog.skillId);
                  setUninstallDialog(null);
                }
              }}
            >
              Yes, uninstall
            </Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>
    </main>
  );
}
