import { api } from "@code/backend/convex/_generated/api";
import type { Id } from "@code/backend/convex/_generated/dataModel";
import { parseAgentEnv } from "@code/env/agent";
import { defineAction } from "@flue/runtime";
import { ConvexHttpClient } from "convex/browser";
import * as v from "valibot";

import {
  createGiteaHttpTransport,
  runPostRunGiteaLifecycle,
} from "../git/gitea";

const pullRequestOutput = v.object({
  baseBranch: v.string(),
  branch: v.string(),
  number: v.number(),
  status: v.picklist(["open", "closed", "merged"]),
  url: v.string(),
});

const output = v.object({
  baseBranch: v.string(),
  branch: v.string(),
  commitSha: v.optional(v.string()),
  pullRequest: v.optional(pullRequestOutput),
  status: v.picklist([
    "no_changes",
    "committed",
    "pushed",
    "pull_request_open",
    "failed",
  ]),
});

export const createFinalizeGiteaLifecycle = (
  issueAgentId: string,
  runtimeEnv: Record<string, string | undefined>
) => {
  const env = parseAgentEnv(runtimeEnv);
  const client = new ConvexHttpClient(env.CONVEX_URL);
  const issueId = issueAgentId as Id<"projectIssues">;

  return defineAction({
    description:
      "After verification, inspect the issue workspace, commit and push its work branch, and create an open Gitea pull request. Never merge.",
    input: v.object({
      commitMessage: v.optional(v.pipe(v.string(), v.maxLength(120))),
      verified: v.boolean(),
    }),
    name: "finalize_gitea_lifecycle",
    output,
    async run({ harness, input, log }) {
      const context = await client.query(api.agentWorkspace.get, {
        issueId,
        token: env.FLUE_DB_TOKEN,
      });
      if (!context.source) {
        throw new Error("Project has no Git source configured");
      }
      if (!context.source.defaultBranch) {
        throw new Error("Project Git source has no default branch");
      }
      if (!env.GITEA_TOKEN) {
        throw new Error(
          "GITEA_TOKEN is required for Gitea pull request creation"
        );
      }

      const runner = {
        async run(
          command: string,
          options?: { cwd?: string; env?: Record<string, string> }
        ) {
          return await harness.shell(command, options);
        },
      };
      const transport = createGiteaHttpTransport({
        baseUrl: env.GITEA_URL,
        token: env.GITEA_TOKEN,
      });

      try {
        const result = await runPostRunGiteaLifecycle({
          baseBranch: context.source.defaultBranch,
          body: `Verified changes for project issue #${context.issue.number}. Merge remains a manual review action.`,
          commitMessage: input.commitMessage,
          issueNumber: context.issue.number,
          issueTitle: context.issue.title,
          repositoryPath: context.source.repositoryPath,
          runner,
          title: `Issue #${context.issue.number}: ${context.issue.title}`,
          transport,
          verification: input.verified ? "passed" : "failed",
          workspace: "/workspace/repository",
        });
        await client.mutation(api.agentWorkspace.recordGiteaLifecycle, {
          baseBranch: result.baseBranch,
          branch: result.branch,
          ...(result.commitSha === undefined
            ? {}
            : { commitSha: result.commitSha }),
          issueId,
          ...(result.pullRequest === undefined
            ? {}
            : { pullRequest: result.pullRequest }),
          status: result.status,
          token: env.FLUE_DB_TOKEN,
        });
        log.info("Gitea lifecycle completed", {
          branch: result.branch,
          status: result.status,
        });
        return result;
      } catch (error) {
        const branchResult = await runner.run("git branch --show-current", {
          cwd: "/workspace/repository",
        });
        const branch = branchResult.stdout.trim() || "unknown";
        const message = error instanceof Error ? error.message : String(error);
        await client.mutation(api.agentWorkspace.recordGiteaLifecycle, {
          baseBranch: context.source.defaultBranch,
          branch,
          error: message,
          issueId,
          status: "failed",
          token: env.FLUE_DB_TOKEN,
        });
        throw error;
      }
    },
  });
};
