import { Injectable, Logger } from "@nestjs/common";
import { Cron } from "@nestjs/schedule";
import { spawn } from "child_process";
import * as path from "path";
import * as fs from "fs";
import { TaskLockService } from "./task-lock.service";

/**
 * Runs the Python `enrich_ai_features.py` script daily to populate the heavy
 * fields (h2h, referee averages, possession, shot conversion, league averages,
 * implied odds, etc.) in football_ai_features rows that were created by
 * FeatureEnrichmentTask but still hold default/zero values.
 *
 * Scheduled at 08:25 IST — between FeatureEnrichmentTask (08:15, creates rows)
 * and PredictionSettlementTask (08:30, reads features for movement calc).
 */
@Injectable()
export class PythonEnrichmentTask {
  private readonly logger = new Logger(PythonEnrichmentTask.name);

  constructor(private readonly taskLock: TaskLockService) {}

  @Cron("25 8 * * *", { timeZone: "Europe/Istanbul" })
  async runHeavyEnrichment() {
    if (process.env.FEEDER_MODE === "historical") {
      this.logger.debug("Skipping python enrichment in historical feeder mode");
      return;
    }
    await this.taskLock.runWithLease(
      "runHeavyEnrichment",
      4 * 60 * 60 * 1000,
      () => this.invokeScript(),
      this.logger,
    );
  }

  private invokeScript(): Promise<void> {
    return new Promise((resolve, reject) => {
      const aiEngineDir = path.resolve(__dirname, "../../ai-engine");
      const scriptPath = path.join(aiEngineDir, "scripts", "enrich_ai_features.py");
      if (!fs.existsSync(scriptPath)) {
        this.logger.warn(`enrich_ai_features.py not found at ${scriptPath}`);
        return resolve();
      }

      const python = this.resolvePythonExecutable(aiEngineDir);
      this.logger.log(`Spawning: ${python} ${scriptPath} --batch-size 500`);

      const child = spawn(python, [scriptPath, "--batch-size", "500"], {
        cwd: aiEngineDir,
        env: { ...process.env, PYTHONIOENCODING: "utf-8" },
      });

      const tail: string[] = [];
      const pushTail = (line: string) => {
        tail.push(line);
        if (tail.length > 40) tail.shift();
      };

      child.stdout.on("data", (buf) => {
        const text = buf.toString("utf-8");
        for (const line of text.split(/\r?\n/)) {
          if (line.trim()) pushTail(line);
        }
      });
      child.stderr.on("data", (buf) => {
        const text = buf.toString("utf-8");
        for (const line of text.split(/\r?\n/)) {
          if (line.trim()) pushTail(`[stderr] ${line}`);
        }
      });

      child.on("error", (err) => {
        this.logger.error(`enrich_ai_features.py spawn error: ${err.message}`);
        reject(err);
      });

      child.on("close", (code) => {
        const lastLines = tail.slice(-10).join("\n");
        if (code === 0) {
          this.logger.log(`enrich_ai_features.py finished cleanly\n${lastLines}`);
          resolve();
        } else {
          this.logger.error(
            `enrich_ai_features.py exited with code ${code}\n${lastLines}`,
          );
          // Non-fatal — don't crash the cron, just log.
          resolve();
        }
      });
    });
  }

  private resolvePythonExecutable(aiEngineDir: string): string {
    const candidates =
      process.platform === "win32"
        ? [
            path.join(aiEngineDir, "venv", "Scripts", "python.exe"),
            path.join(aiEngineDir, ".venv", "Scripts", "python.exe"),
            "python",
          ]
        : [
            path.join(aiEngineDir, "venv", "bin", "python3"),
            path.join(aiEngineDir, "venv", "bin", "python"),
            "python3",
            "python",
          ];
    for (const candidate of candidates) {
      if (candidate.includes(path.sep) && fs.existsSync(candidate)) return candidate;
    }
    return candidates[candidates.length - 1];
  }
}
