import { api } from "@code/backend/convex/_generated/api";
import type { Id } from "@code/backend/convex/_generated/dataModel";
import { useAction, useMutation, useQuery } from "convex/react";
import { useState } from "react";

import { flueClient } from "@/root";

const errorMessage = (error: unknown) =>
  error instanceof Error ? error.message : String(error);

export const useProjectWorkspace = () => {
  const projects = useQuery(api.projects.list);
  const [selectedProjectId, setSelectedProjectId] =
    useState<Id<"projects"> | null>(null);
  const [repository, setRepository] = useState("");
  const [issueTitle, setIssueTitle] = useState("");
  const [issueBody, setIssueBody] = useState("");
  const [pendingAction, setPendingAction] = useState<string | null>(null);
  const [error, setError] = useState<string | null>(null);
  const connectGitHub = useAction(api.projects.connectGitHub);
  const createIssue = useMutation(api.projectIssues.create);
  const beginIssue = useMutation(api.projectIssues.begin);
  const markDispatchFailed = useMutation(api.projectIssues.markDispatchFailed);
  const activeProjectId = selectedProjectId ?? projects?.[0]?._id ?? null;
  const artifacts = useQuery(
    api.projectArtifacts.list,
    activeProjectId ? { projectId: activeProjectId } : "skip"
  );
  const issues = useQuery(
    api.projectIssues.list,
    activeProjectId ? { projectId: activeProjectId } : "skip"
  );

  const connectRepository = async () => {
    setPendingAction("connect");
    setError(null);
    try {
      const projectId = await connectGitHub({ repository });
      setSelectedProjectId(projectId);
      setRepository("");
    } catch (caughtError) {
      setError(errorMessage(caughtError));
    } finally {
      setPendingAction(null);
    }
  };

  const raiseIssue = async () => {
    if (!activeProjectId) {
      return;
    }
    setPendingAction("issue");
    setError(null);
    try {
      await createIssue({
        body: issueBody,
        projectId: activeProjectId,
        title: issueTitle,
      });
      setIssueTitle("");
      setIssueBody("");
    } catch (caughtError) {
      setError(errorMessage(caughtError));
    } finally {
      setPendingAction(null);
    }
  };

  const startIssue = async (
    issueId: Id<"projectIssues">,
    issueNumber: number,
    title: string
  ) => {
    const actionKey = `issue:${issueId}`;
    setPendingAction(actionKey);
    setError(null);
    try {
      await beginIssue({ issueId });
      await flueClient.agents.send("project-manager", String(issueId), {
        message: `Start project issue ${issueNumber}: ${title}. Read the bound context and complete the workflow.`,
      });
    } catch (caughtError) {
      const message = errorMessage(caughtError);
      await markDispatchFailed({ error: message, issueId });
      setError(message);
    } finally {
      setPendingAction(null);
    }
  };

  const selectedProject =
    projects?.find((project) => project._id === activeProjectId) ?? null;

  return {
    artifacts,
    connectRepository,
    error,
    issueBody,
    issueTitle,
    issues,
    pendingAction,
    projects,
    raiseIssue,
    repository,
    selectedProject,
    selectedProjectId: activeProjectId,
    setIssueBody,
    setIssueTitle,
    setRepository,
    setSelectedProjectId,
    startIssue,
  } as const;
};
