import { Injectable, Logger, OnModuleInit } from "@nestjs/common";
import * as fs from "fs";
import * as path from "path";
import axios from "axios";
// Canvas is optional – native module may fail on ARM64 (RPi)
let createCanvas: any;
let loadImage: any;
try {
  const canvas = require("canvas");
  createCanvas = canvas.createCanvas;
  loadImage = canvas.loadImage;
} catch {
  // Canvas unavailable – ImageRendererService methods will throw at runtime if called
}
import { PredictionCardDto } from "./dto/prediction-card.dto";

@Injectable()
export class ImageRendererService implements OnModuleInit {
  private readonly logger = new Logger(ImageRendererService.name);
  private readonly outputDir = path.join(
    process.cwd(),
    "public",
    "predictions",
  );

  onModuleInit() {
    // Ensure output directory exists
    if (!fs.existsSync(this.outputDir)) {
      fs.mkdirSync(this.outputDir, { recursive: true });
    }
  }

  /**
   * Render a prediction card to a PNG image using Canvas API.
   * Returns the file path of the generated image.
   */
  async renderCard(card: PredictionCardDto): Promise<string> {
    const fileName = `prediction_${card.matchId}_${Date.now()}.png`;
    const filePath = path.join(this.outputDir, fileName);

    try {
      this.logger.log(
        `🎨 Rendering canvas for ${card.homeTeam} vs ${card.awayTeam}...`,
      );
      await this.drawCanvas(card, filePath);
      this.logger.log(`✅ Card rendered to ${fileName}`);
      return filePath;
    } catch (error) {
      this.logger.error(`Failed to render canvas card: ${error.message}`);
      throw error;
    }
  }

  /**
   * Load a team logo image. Handles:
   * 1. Local file path (e.g., /uploads/teams/xxx.png → public/uploads/teams/xxx.png)
   * 2. Full HTTP URL (e.g., https://cdn.example.com/logo.png)
   * 3. Mackolik CDN fallback using team slug from path
   */
  private async downloadImage(url: string) {
    if (!url) return null;

    try {
      // Case 1: Local relative path → read from public/ directory
      if (url.startsWith("/")) {
        const localPath = path.join(process.cwd(), "public", url);
        if (fs.existsSync(localPath)) {
          this.logger.debug(`Loading logo from local file: ${localPath}`);
          return await loadImage(localPath);
        }
        // Local file not found → try as full URL via APP_BASE_URL
        this.logger.debug(
          `Local file not found: ${localPath}, trying remote...`,
        );
      }

      // Case 2: Full HTTP/HTTPS URL → fetch directly
      if (url.startsWith("http")) {
        const response = await axios.get(url, {
          responseType: "arraybuffer",
          timeout: 5000,
        });
        return await loadImage(response.data);
      }

      this.logger.warn(`Could not resolve logo path: ${url}`);
      return null;
    } catch (error) {
      this.logger.warn(`Could not load image from ${url}: ${error.message}`);
      return null;
    }
  }

  private fillRoundRect(
    ctx: any,
    x: number,
    y: number,
    width: number,
    height: number,
    radius: number,
  ) {
    ctx.beginPath();
    ctx.moveTo(x + radius, y);
    ctx.lineTo(x + width - radius, y);
    ctx.quadraticCurveTo(x + width, y, x + width, y + radius);
    ctx.lineTo(x + width, y + height - radius);
    ctx.quadraticCurveTo(x + width, y + height, x + width - radius, y + height);
    ctx.lineTo(x + radius, y + height);
    ctx.quadraticCurveTo(x, y + height, x, y + height - radius);
    ctx.lineTo(x, y + radius);
    ctx.quadraticCurveTo(x, y, x + radius, y);
    ctx.closePath();
    ctx.fill();
  }

  private strokeRoundRect(
    ctx: any,
    x: number,
    y: number,
    width: number,
    height: number,
    radius: number,
  ) {
    ctx.beginPath();
    ctx.moveTo(x + radius, y);
    ctx.lineTo(x + width - radius, y);
    ctx.quadraticCurveTo(x + width, y, x + width, y + radius);
    ctx.lineTo(x + width, y + height - radius);
    ctx.quadraticCurveTo(x + width, y + height, x + width - radius, y + height);
    ctx.lineTo(x + radius, y + height);
    ctx.quadraticCurveTo(x, y + height, x, y + height - radius);
    ctx.lineTo(x, y + radius);
    ctx.quadraticCurveTo(x, y, x + radius, y);
    ctx.closePath();
    ctx.stroke();
  }

  private async drawCanvas(
    data: PredictionCardDto,
    outPath: string,
  ): Promise<void> {
    const width = 1080;
    const height = 1920;
    const canvas = createCanvas(width, height);
    const ctx = canvas.getContext("2d");

    // Background Gradient
    const bgGrad = ctx.createLinearGradient(0, 0, width, height);
    bgGrad.addColorStop(0, "#0a0e27");
    bgGrad.addColorStop(0.35, "#1a1040");
    bgGrad.addColorStop(0.7, "#0d1b2a");
    bgGrad.addColorStop(1, "#0a0e27");
    ctx.fillStyle = bgGrad;
    ctx.fillRect(0, 0, width, height);

    // Watermark
    ctx.save();
    ctx.translate(width / 2, height / 2);
    ctx.rotate((-35 * Math.PI) / 180);
    ctx.fillStyle = "rgba(255, 255, 255, 0.05)";
    ctx.font = "900 100px sans-serif";
    ctx.textAlign = "center";
    ctx.textBaseline = "middle";
    const wmLine =
      "iddaai.com    iddaai.com    iddaai.com    iddaai.com    iddaai.com    iddaai.com    iddaai.com    iddaai.com";
    for (let i = -15; i <= 15; i++) {
      ctx.fillText(wmLine, 0, i * 180);
    }
    ctx.restore();

    // Settings
    const paddingX = 80;

    // Header
    ctx.fillStyle = "rgba(255, 255, 255, 0.7)";
    ctx.font = "600 28px sans-serif";
    ctx.textAlign = "left";
    ctx.fillText(data.leagueName.toUpperCase(), paddingX, 120);

    ctx.fillStyle = "rgba(255, 255, 255, 0.45)";
    ctx.font = "400 22px sans-serif";
    ctx.textAlign = "right";
    ctx.fillText(data.matchDate, width - paddingX, 120);

    // Teams Section
    let currentY = 280;
    const [homeImg, awayImg] = await Promise.all([
      this.downloadImage(data.homeLogo),
      this.downloadImage(data.awayLogo),
    ]);

    if (homeImg) ctx.drawImage(homeImg, width / 4 - 100, currentY, 200, 200);
    if (awayImg)
      ctx.drawImage(awayImg, (width / 4) * 3 - 100, currentY, 200, 200);

    ctx.fillStyle = "rgba(255, 255, 255, 0.15)";
    ctx.font = "900 56px sans-serif";
    ctx.textAlign = "center";
    ctx.fillText("VS", width / 2, currentY + 110);

    currentY += 250;
    ctx.fillStyle = "#ffffff";
    ctx.font = "700 36px sans-serif";
    ctx.textAlign = "center";
    ctx.fillText(data.homeTeam, width / 4, currentY);
    ctx.fillText(data.awayTeam, (width / 4) * 3, currentY);

    // Divider: Skore Prediction
    currentY += 140;
    const drawSectionTitle = (y: number, text: string) => {
      ctx.textAlign = "center";
      ctx.fillStyle = "rgba(255, 255, 255, 0.5)";
      ctx.font = "600 22px sans-serif";
      ctx.fillText(text, width / 2, y + 8);

      const txtWidth = ctx.measureText(text).width;
      const grad = ctx.createLinearGradient(paddingX, y, width - paddingX, y);
      grad.addColorStop(0, "rgba(120, 80, 255, 0)");
      grad.addColorStop(0.5, "rgba(120, 80, 255, 0.6)");
      grad.addColorStop(1, "rgba(120, 80, 255, 0)");

      ctx.fillStyle = grad;
      ctx.fillRect(
        paddingX,
        y - 2,
        (width - 2 * paddingX - txtWidth - 40) / 2,
        3,
      );
      ctx.fillRect(
        width / 2 + txtWidth / 2 + 20,
        y - 2,
        (width - 2 * paddingX - txtWidth - 40) / 2,
        3,
      );
    };

    drawSectionTitle(currentY, "SKOR TAHMİNİ / SCORE PREDICTION");

    // Scores
    currentY += 80;
    const scoreBoxWidth = 380;
    const scoreBoxHeight = 220;
    const htX = width / 2 - scoreBoxWidth - 24;
    const ftX = width / 2 + 24;

    // HT Box
    ctx.fillStyle = "rgba(255, 255, 255, 0.04)";
    ctx.strokeStyle = "rgba(255, 255, 255, 0.08)";
    ctx.lineWidth = 2;
    this.fillRoundRect(ctx, htX, currentY, scoreBoxWidth, scoreBoxHeight, 20);
    this.strokeRoundRect(ctx, htX, currentY, scoreBoxWidth, scoreBoxHeight, 20);

    ctx.fillStyle = "rgba(255, 255, 255, 0.45)";
    ctx.font = "600 20px sans-serif";
    ctx.fillText("İLK YARI", htX + scoreBoxWidth / 2, currentY + 40);
    ctx.fillStyle = "rgba(255, 255, 255, 0.25)";
    ctx.font = "400 16px sans-serif";
    ctx.fillText("Half Time", htX + scoreBoxWidth / 2, currentY + 65);
    ctx.fillStyle = "#ffffff";
    ctx.font = "900 80px sans-serif";
    ctx.fillText(data.htScore, htX + scoreBoxWidth / 2, currentY + 160);

    // FT Box
    const ftGrad = ctx.createLinearGradient(
      ftX,
      currentY,
      ftX + scoreBoxWidth,
      currentY + scoreBoxHeight,
    );
    ftGrad.addColorStop(0, "rgba(120, 80, 255, 0.15)");
    ftGrad.addColorStop(1, "rgba(0, 200, 255, 0.1)");
    ctx.fillStyle = ftGrad;
    ctx.strokeStyle = "rgba(120, 80, 255, 0.3)";
    this.fillRoundRect(ctx, ftX, currentY, scoreBoxWidth, scoreBoxHeight, 20);
    this.strokeRoundRect(ctx, ftX, currentY, scoreBoxWidth, scoreBoxHeight, 20);

    ctx.fillStyle = "rgba(255, 255, 255, 0.45)";
    ctx.font = "600 20px sans-serif";
    ctx.fillText("MAÇ SONU", ftX + scoreBoxWidth / 2, currentY + 40);
    ctx.fillStyle = "rgba(255, 255, 255, 0.25)";
    ctx.font = "400 16px sans-serif";
    ctx.fillText("Full Time", ftX + scoreBoxWidth / 2, currentY + 65);

    // Score text gradient
    const txtGrad = ctx.createLinearGradient(
      ftX,
      currentY + 100,
      ftX,
      currentY + 160,
    );
    txtGrad.addColorStop(0, "#9b6fff");
    txtGrad.addColorStop(1, "#00c8ff");
    ctx.fillStyle = txtGrad;
    ctx.font = "900 80px sans-serif";
    ctx.fillText(data.ftScore, ftX + scoreBoxWidth / 2, currentY + 160);

    // Confidence badge
    ctx.fillStyle = "#0a0e27";
    ctx.strokeStyle = "rgba(120, 80, 255, 0.6)";
    this.fillRoundRect(
      ctx,
      ftX + scoreBoxWidth / 2 - 80,
      currentY + scoreBoxHeight - 20,
      160,
      40,
      20,
    );
    this.strokeRoundRect(
      ctx,
      ftX + scoreBoxWidth / 2 - 80,
      currentY + scoreBoxHeight - 20,
      160,
      40,
      20,
    );
    ctx.fillStyle = "#b89dff";
    ctx.font = "800 20px sans-serif";
    ctx.fillText(
      `🎯 %${data.scoreConfidence}`,
      ftX + scoreBoxWidth / 2,
      currentY + scoreBoxHeight + 7,
    );

    // Divider: Picks
    currentY += scoreBoxHeight + 100;
    drawSectionTitle(currentY, "EN İYİ TAHMİNLER / BEST PICKS");

    // Picks rendering
    currentY += 80;
    data.topPicks.forEach((pick, index) => {
      ctx.fillStyle = "rgba(255, 255, 255, 0.03)";
      ctx.strokeStyle = "rgba(255, 255, 255, 0.06)";
      this.fillRoundRect(
        ctx,
        paddingX,
        currentY,
        width - 2 * paddingX,
        100,
        16,
      );
      this.strokeRoundRect(
        ctx,
        paddingX,
        currentY,
        width - 2 * paddingX,
        100,
        16,
      );

      ctx.fillStyle = "rgba(255, 255, 255, 0.3)";
      ctx.font = "700 28px sans-serif";
      ctx.textAlign = "left";
      ctx.fillText(String(index + 1), paddingX + 30, currentY + 58);

      ctx.fillStyle = "#ffffff";
      ctx.font = "600 26px sans-serif";
      ctx.fillText(pick.market, paddingX + 80, currentY + 45);

      const marketWidth = ctx.measureText(pick.market).width;
      ctx.fillStyle = "rgba(255, 255, 255, 0.35)";
      ctx.font = "400 18px sans-serif";
      ctx.fillText(
        `(${pick.marketEn})`,
        paddingX + 80 + marketWidth + 10,
        currentY + 43,
      );

      // Pick Bar bg
      ctx.fillStyle = "rgba(255, 255, 255, 0.06)";
      const barMaxWidth = width - 2 * paddingX - 220;
      this.fillRoundRect(ctx, paddingX + 80, currentY + 65, barMaxWidth, 12, 6);

      // Pick Bar fill
      const fillWidth = (pick.confidence / 100) * barMaxWidth;
      const barGrad = ctx.createLinearGradient(
        paddingX + 80,
        0,
        paddingX + 80 + barMaxWidth,
        0,
      );
      barGrad.addColorStop(0, "#7850ff");
      barGrad.addColorStop(1, "#00c8ff");
      ctx.fillStyle = barGrad;
      this.fillRoundRect(ctx, paddingX + 80, currentY + 65, fillWidth, 12, 6);

      // Confidence text
      ctx.fillStyle = "#b89dff";
      ctx.font = "900 32px sans-serif";
      ctx.textAlign = "right";
      ctx.fillText(`%${pick.confidence}`, width - paddingX - 30, currentY + 58);

      currentY += 124;
    });

    // Footer
    currentY = height - 80;
    ctx.fillStyle = "rgba(255, 255, 255, 0.4)";
    ctx.font = "700 26px sans-serif";
    ctx.textAlign = "left";
    ctx.fillText("⚡ AI Powered by SuggestBet", paddingX, currentY);

    let riskBg, riskColor, riskBorder;
    switch (data.riskLevel) {
      case "LOW":
        riskBg = "rgba(0, 200, 100, 0.15)";
        riskColor = "#4ade80";
        riskBorder = "rgba(0, 200, 100, 0.3)";
        break;
      case "MEDIUM":
        riskBg = "rgba(255, 200, 0, 0.12)";
        riskColor = "#fbbf24";
        riskBorder = "rgba(255, 200, 0, 0.25)";
        break;
      case "HIGH":
        riskBg = "rgba(255, 100, 50, 0.12)";
        riskColor = "#f97316";
        riskBorder = "rgba(255, 100, 50, 0.25)";
        break;
      case "EXTREME":
        riskBg = "rgba(255, 50, 50, 0.15)";
        riskColor = "#ef4444";
        riskBorder = "rgba(255, 50, 50, 0.3)";
        break;
      default:
        riskBg = "rgba(255, 255, 255, 0.1)";
        riskColor = "#ffffff";
        riskBorder = "rgba(255, 255, 255, 0.3)";
    }

    const riskText = `RISK: ${data.riskLevel}`;
    ctx.font = "800 20px sans-serif";
    const riskWidth = ctx.measureText(riskText).width;
    ctx.fillStyle = riskBg;
    ctx.strokeStyle = riskBorder;
    this.fillRoundRect(
      ctx,
      width - paddingX - riskWidth - 48,
      currentY - 26,
      riskWidth + 48,
      44,
      22,
    );
    this.strokeRoundRect(
      ctx,
      width - paddingX - riskWidth - 48,
      currentY - 26,
      riskWidth + 48,
      44,
      22,
    );

    ctx.fillStyle = riskColor;
    ctx.textAlign = "center";
    ctx.fillText(riskText, width - paddingX - riskWidth / 2 - 24, currentY + 3);

    // Save Output directly using the buffer
    const buffer = canvas.toBuffer("image/png");
    fs.writeFileSync(outPath, buffer);
  }

  /**
   * Get the web-accessible URL for a rendered image.
   */
  getImageUrl(filePath: string): string {
    const relativePath = path.relative(
      path.join(process.cwd(), "public"),
      filePath,
    );
    return `/${relativePath.replace(/\\/g, "/")}`;
  }
}
