import {
  cloneRepo,
  commitAll,
  createBranch,
  pushBranch,
  removeRepo,
  writeBinaryFile,
  writeFile,
} from "./gitClient";
import { makePullRequest } from "./giteaClient";
import { notifyDiscord } from "./discordNotifier";
import { eventRelativePath, posterRelativePath, renderEventMarkdown } from "./eventFile";
import { fetchAndValidatePoster } from "./posterHandler";
import { Job } from "./types";
import { updateJob } from "./jobStore";

function requiredEnv(name: string): string {
  const value = process.env[name];
  if (!value) {
    throw new Error(`Missing required env var ${name}`);
  }
  return value;
}

// Runs the full pipeline for a job: clone -> branch -> write file -> commit
// -> push -> open PR (or skip if no Gitea credentials) -> notify Discord
// (or skip if not configured). Mutates the job in jobStore as it progresses
// so GET /api/events/:requestId reflects the latest state even if the
// original POST's connection was dropped.
export async function runPublishJob(job: Job): Promise<void> {
  const { requestId, requestBody } = job;
  const { event, submittedByEmail } = requestBody;

  const targetSshUrl = requiredEnv("TARGET_GIT_SSH_URL");
  const baseOwner = requiredEnv("PR_OWNER");
  const repoName = requiredEnv("PR_REPONAME");
  const headOwner = process.env.FORK_OWNER || baseOwner;

  const branchName = `event/${event.slug}`;
  let repoPath: string | null = null;

  try {
    repoPath = await cloneRepo(targetSshUrl);
    createBranch(repoPath, branchName);

    let posterPath: string | undefined;
    if (event.poster) {
      const fetched = await fetchAndValidatePoster(event.poster);
      posterPath = posterRelativePath(event, fetched.filename);
      await writeBinaryFile(repoPath, posterPath, fetched.buffer);
    }

    const relativePath = eventRelativePath(event);
    await writeFile(repoPath, relativePath, renderEventMarkdown(event, posterPath));

    commitAll(repoPath, `Add event: ${event.name}`);
    pushBranch(repoPath, branchName, headOwner === baseOwner ? "origin" : headOwner);

    const title = `[Event] ${event.name}`;
    const body =
      `Auto-generated by EventCentral.\n\n` +
      `Submitted by: ${submittedByEmail}\n` +
      `Request ID: ${requestId}\n\n` +
      `Please review the event details and merge if correct.`;

    const prResult = await makePullRequest(baseOwner, repoName, headOwner, branchName, title, body);

    const discordOutcome = await notifyDiscord(event, prResult.url);

    updateJob(requestId, {
      status: prResult.created ? "pr_created" : "pr_skipped_no_credentials",
      branchName,
      pullRequestUrl: prResult.url,
      discord: discordOutcome,
    });
  } catch (error) {
    updateJob(requestId, {
      status: "failed",
      branchName,
      error: error instanceof Error ? error.message : String(error),
    });
  } finally {
    if (repoPath) {
      await removeRepo(repoPath);
    }
  }
}
