import { Injectable, Logger } from "@nestjs/common";
import { ConfigService } from "@nestjs/config";
import { spawn } from "child_process";

export type PublishStatus = "idle" | "running" | "success" | "failed";

/**
 * Triggers a rebuild of the static frontend export so published content
 * changes actually land in the shipped HTML (the site is `output: "export"`
 * — see frontend/next.config.ts — so nothing goes live until it's rebuilt).
 *
 * This runs `npm run build` in the frontend directory as a detached child
 * process and tracks its last result in memory. It does NOT deploy the
 * resulting `frontend/out` folder anywhere — on cPanel that's a separate
 * upload/sync step outside this API's reach from shared hosting. Swap this
 * for a real CI/deploy webhook when one exists.
 */
@Injectable()
export class PublishService {
  private readonly logger = new Logger(PublishService.name);
  private status: PublishStatus = "idle";
  private lastOutput = "";
  private lastRunAt: Date | null = null;

  constructor(private readonly config: ConfigService) {}

  getStatus() {
    return { status: this.status, lastRunAt: this.lastRunAt, lastOutput: this.lastOutput.slice(-4000) };
  }

  trigger(): { started: boolean; status: PublishStatus } {
    if (this.status === "running") {
      return { started: false, status: this.status };
    }

    const frontendDir = this.config.get<string>("FRONTEND_DIR");
    if (!frontendDir) {
      this.status = "failed";
      this.lastOutput = "FRONTEND_DIR is not set in .env — can't locate the frontend project to build.";
      return { started: false, status: this.status };
    }

    this.status = "running";
    this.lastOutput = "";
    this.lastRunAt = new Date();

    // Windows can't spawn a .cmd shim directly without a shell (EINVAL) —
    // shell: true routes it through cmd.exe, same as running it yourself.
    const isWindows = process.platform === "win32";
    const child = spawn("npm", ["run", "build"], {
      cwd: frontendDir,
      shell: isWindows,
    });

    child.stdout.on("data", (chunk) => (this.lastOutput += chunk.toString()));
    child.stderr.on("data", (chunk) => (this.lastOutput += chunk.toString()));
    child.on("error", (err) => {
      this.status = "failed";
      this.lastOutput += `\n${err.message}`;
      this.logger.error(`Publish build failed to start: ${err.message}`);
    });
    child.on("exit", (code) => {
      this.status = code === 0 ? "success" : "failed";
      this.logger.log(`Publish build finished with exit code ${code}`);
    });

    return { started: true, status: this.status };
  }
}
