import { gitBranchSummary, gitCommitCount, gitIsStarred, gitReadme, gitStar, gitStarCount, gitUnstar, gitWatchCount, gitIsWatched, gitWatch, gitUnwatch, gitTagCount } from "@/client";
import { RepoHeader } from "@/components/repository/header";
import { Button } from "@/components/ui/button";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { GitBranch, GitCommit, GitMerge, Loader2, Star, Tag, Users, Eye } from "lucide-react";
import { useRepo } from "@/contexts";
import { toast } from "sonner";

export const RepoOverview = () => {
  const repo = useRepo();
  const queryClient = useQueryClient();

  const { data: readmeData } = useQuery({
    queryKey: ["repo-readme", repo?.namespace, repo?.repo_name],
    queryFn: async () => {
      if (!repo?.namespace || !repo?.repo_name) return null;
      const resp = await gitReadme({
        path: { namespace: repo.namespace, repo: repo.repo_name },
      });
      return resp.data?.data ?? null;
    },
    enabled: !!repo?.namespace && !!repo?.repo_name,
    staleTime: 5 * 60 * 1000,
  });

  const { data: commitCountData } = useQuery({
    queryKey: ["repo-commit-count", repo?.namespace, repo?.repo_name],
    queryFn: async () => {
      if (!repo?.namespace || !repo?.repo_name) return null;
      const resp = await gitCommitCount({ path: { namespace: repo.namespace, repo: repo.repo_name } });
      return resp.data?.data ?? null;
    },
    enabled: !!repo?.namespace && !!repo?.repo_name,
    staleTime: 60 * 1000,
  });

  const { data: branchSummaryData } = useQuery({
    queryKey: ["repo-branch-summary", repo?.namespace, repo?.repo_name],
    queryFn: async () => {
      if (!repo?.namespace || !repo?.repo_name) return null;
      const resp = await gitBranchSummary({ path: { namespace: repo.namespace, repo: repo.repo_name } });
      return resp.data?.data ?? null;
    },
    enabled: !!repo?.namespace && !!repo?.repo_name,
    staleTime: 60 * 1000,
  });

  const { data: starCountData } = useQuery({
    queryKey: ["repo-star-count", repo?.namespace, repo?.repo_name],
    queryFn: async () => {
      if (!repo?.namespace || !repo?.repo_name) return null;
      const resp = await gitStarCount({ path: { namespace: repo.namespace, repo: repo.repo_name } });
      return resp.data?.data ?? null;
    },
    enabled: !!repo?.namespace && !!repo?.repo_name,
    staleTime: 60 * 1000,
  });

  const { data: watchCountData } = useQuery({
    queryKey: ["repo-watch-count", repo?.namespace, repo?.repo_name],
    queryFn: async () => {
      if (!repo?.namespace || !repo?.repo_name) return null;
      const resp = await gitWatchCount({ path: { namespace: repo.namespace, repo: repo.repo_name } });
      return resp.data?.data ?? null;
    },
    enabled: !!repo?.namespace && !!repo?.repo_name,
    staleTime: 60 * 1000,
  });

  const { data: isStarredData } = useQuery({
    queryKey: ["repo-is-starred", repo?.namespace, repo?.repo_name],
    queryFn: async () => {
      if (!repo?.namespace || !repo?.repo_name) return null;
      const resp = await gitIsStarred({ path: { namespace: repo.namespace, repo: repo.repo_name } });
      return resp.data?.data ?? null;
    },
    enabled: !!repo?.namespace && !!repo?.repo_name,
    staleTime: 30 * 1000,
    retry: false,
  });

  const { data: isWatchedData } = useQuery({
    queryKey: ["repo-is-watched", repo?.namespace, repo?.repo_name],
    queryFn: async () => {
      if (!repo?.namespace || !repo?.repo_name) return null;
      const resp = await gitIsWatched({ path: { namespace: repo.namespace, repo: repo.repo_name } });
      return resp.data?.data ?? null;
    },
    enabled: !!repo?.namespace && !!repo?.repo_name,
    staleTime: 30 * 1000,
    retry: false,
  });

  const { data: tagCountData } = useQuery({
    queryKey: ["repo-tag-count", repo?.namespace, repo?.repo_name],
    queryFn: async () => {
      if (!repo?.namespace || !repo?.repo_name) return null;
      const resp = await gitTagCount({ path: { namespace: repo.namespace, repo: repo.repo_name } });
      return resp.data?.data ?? null;
    },
    enabled: !!repo?.namespace && !!repo?.repo_name,
    staleTime: 60 * 1000,
  });

  const starMutation = useMutation({
    mutationFn: async () => {
      if (!repo?.namespace || !repo?.repo_name) return;
      await gitStar({ path: { namespace: repo.namespace, repo: repo.repo_name } });
    },
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ["repo-is-starred", repo?.namespace, repo?.repo_name] });
      queryClient.invalidateQueries({ queryKey: ["repo-star-count", repo?.namespace, repo?.repo_name] });
      toast.success("Starred");
    },
    onError: () => {
      toast.error("Failed to star");
    },
  });

  const unstarMutation = useMutation({
    mutationFn: async () => {
      if (!repo?.namespace || !repo?.repo_name) return;
      await gitUnstar({ path: { namespace: repo.namespace, repo: repo.repo_name } });
    },
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ["repo-is-starred", repo?.namespace, repo?.repo_name] });
      queryClient.invalidateQueries({ queryKey: ["repo-star-count", repo?.namespace, repo?.repo_name] });
      toast.success("Unstarred");
    },
    onError: () => {
      toast.error("Failed to unstar");
    },
  });

  const watchMutation = useMutation({
    mutationFn: async () => {
      if (!repo?.namespace || !repo?.repo_name) return;
      await gitWatch({ path: { namespace: repo.namespace, repo: repo.repo_name }, body: {} });
    },
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ["repo-is-watched", repo?.namespace, repo?.repo_name] });
      queryClient.invalidateQueries({ queryKey: ["repo-watch-count", repo?.namespace, repo?.repo_name] });
      toast.success("Watching repository");
    },
    onError: () => {
      toast.error("Failed to watch");
    },
  });

  const unwatchMutation = useMutation({
    mutationFn: async () => {
      if (!repo?.namespace || !repo?.repo_name) return;
      await gitUnwatch({ path: { namespace: repo.namespace, repo: repo.repo_name } });
    },
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ["repo-is-watched", repo?.namespace, repo?.repo_name] });
      queryClient.invalidateQueries({ queryKey: ["repo-watch-count", repo?.namespace, repo?.repo_name] });
      toast.success("Stopped watching");
    },
    onError: () => {
      toast.error("Failed to unwatch");
    },
  });

  const readmeContent = (() => {
    if (!readmeData?.content) return null;
    try {
      return atob(readmeData.content);
    } catch {
      return null;
    }
  })();

  if (!repo) {
    return (
      <div className="flex items-center justify-center h-full">
        <p className="text-muted-foreground">Loading...</p>
      </div>
    );
  }

  return (
    <>
      <div className="p-6 pb-0 max-w-5xl mx-auto space-y-6">
        <RepoHeader />
      </div>
      <div className="p-6 pt-0 max-w-5xl mx-auto space-y-6">
        <div className="border rounded-md">
          <div className="px-4 py-2 border-b text-sm font-medium">Repository Stats</div>
          <div className="p-6">
            <div className="grid grid-cols-2 md:grid-cols-4 gap-6">
              <StatCard icon={<GitBranch className="h-5 w-5" />} label="Default branch" value={repo.default_branch} />
              <StatCard icon={<GitCommit className="h-5 w-5" />} label="Commits" value={commitCountData?.count?.toLocaleString() ?? repo.commit_count} />
              <StatCard icon={<GitMerge className="h-5 w-5" />} label="Branches" value={branchSummaryData?.local_count ?? repo.branch_count} />
              <StatCard icon={<Tag className="h-5 w-5" />} label="Tags" value={tagCountData?.count?.toLocaleString() ?? repo.tag_count} />
              <div className="flex items-center gap-3">
                <div className="text-muted-foreground"><Star className="h-5 w-5" /></div>
                <div>
                  <div className="text-xs text-muted-foreground">Stars</div>
                  <div className="font-medium tabular-nums flex items-center gap-2">
                    {starCountData?.count?.toLocaleString() ?? repo.star_count}
                    {(starMutation.isPending || unstarMutation.isPending) ? (
                      <Loader2 className="h-3 w-3 animate-spin" />
                    ) : (
                      <Button
                        variant="ghost"
                        size="sm"
                        className="h-6 px-2"
                        onClick={() => isStarredData ? unstarMutation.mutate() : starMutation.mutate()}
                      >
                        <Star className={`h-3 w-3 ${isStarredData ? "fill-yellow-400 text-yellow-400" : ""}`} />
                      </Button>
                    )}
                  </div>
                </div>
              </div>
              <div className="flex items-center gap-3">
                <div className="text-muted-foreground"><Users className="h-5 w-5" /></div>
                <div>
                  <div className="text-xs text-muted-foreground">Watchers</div>
                  <div className="font-medium tabular-nums flex items-center gap-2">
                    {watchCountData?.count?.toLocaleString() ?? repo.watch_count}
                    {(watchMutation.isPending || unwatchMutation.isPending) ? (
                      <Loader2 className="h-3 w-3 animate-spin" />
                    ) : (
                      <Button
                        variant="ghost"
                        size="sm"
                        className="h-6 px-2"
                        onClick={() => isWatchedData ? unwatchMutation.mutate() : watchMutation.mutate()}
                      >
                        <Eye className={`h-3 w-3 ${isWatchedData ? "fill-blue-400 text-blue-400" : ""}`} />
                      </Button>
                    )}
                  </div>
                </div>
              </div>
            </div>
          </div>
        </div>

        {readmeContent !== undefined && (
          <div className="border rounded-md">
            <div className="px-4 py-2 border-b text-sm font-medium">
              {readmeData?.path ?? "README"}
            </div>
            <div className="p-6">
              <pre className="whitespace-pre-wrap text-sm text-muted-foreground font-sans leading-relaxed">
                {readmeContent}
              </pre>
            </div>
          </div>
        )}
      </div>
    </>
  );
};

const StatCard = ({
  icon,
  label,
  value,
}: {
  icon: React.ReactNode;
  label: string;
  value: React.ReactNode;
}) => (
  <div className="flex items-center gap-3">
    <div className="text-muted-foreground">{icon}</div>
    <div>
      <div className="text-xs text-muted-foreground">{label}</div>
      <div className="font-medium tabular-nums">{value}</div>
    </div>
  </div>
);
