import { FastifyInstance } from "fastify";
import * as fs from "node:fs";
import * as path from "node:path";
import { fileURLToPath } from "node:url";
import type { RouteContext } from "./types.js";

/**
 * Routes pour servir les images d'avatars de manière sécurisée
 * Vérifie que l'utilisateur possède l'avatar avant de servir l'image
 */
export async function registerAvatarImageRoutes(
  app: FastifyInstance,
  ctx: RouteContext,
) {
  const { db, requireAuth } = ctx;
  const moduleDir = path.dirname(fileURLToPath(import.meta.url));

  // Utilitaire: calculer la clé de semaine ISO (YYYY-WXX)
  const getWeekKey = (date: Date = new Date()): string => {
    const d = new Date(date);
    d.setHours(0, 0, 0, 0);
    d.setDate(d.getDate() + 3 - ((d.getDay() + 6) % 7));
    const week1 = new Date(d.getFullYear(), 0, 4);
    const weekNumber =
      Math.round(
        ((d.getTime() - week1.getTime()) / 86400000 -
          3 +
          ((week1.getDay() + 6) % 7)) /
          7,
      ) + 1;
    return `${d.getFullYear()}-W${String(weekNumber).padStart(2, "0")}`;
  };

  /**
   * GET /avatars/weekly-reward/:avatarId/image
   * Sert l'avatar de récompense hebdomadaire (preview), sans exiger que l'utilisateur le possède.
   * Sécurité: accessible uniquement si :avatarId correspond à la récompense de la semaine courante.
   */
  app.get<{
    Params: { avatarId: string };
  }>(
    "/avatars/weekly-reward/:avatarId/image",
    { preHandler: requireAuth },
    async (request, reply) => {
      const userId = request.user?.sub;
      if (!userId) {
        return reply.code(401).send({ error: "Authentification requise" });
      }

      const raw = decodeURIComponent(request.params.avatarId);
      const avatarId = Number(raw);
      if (!Number.isFinite(avatarId) || avatarId < 1 || avatarId > 380) {
        return reply.code(400).send({ error: "Format avatarId invalide" });
      }

      const weekKey = getWeekKey();
      const [rows] = await db.execute(
        "SELECT 1 FROM weekly_rewards WHERE week_key = ? AND avatar_id = ? LIMIT 1",
        [weekKey, avatarId],
      );
      if (!Array.isArray(rows) || rows.length === 0) {
        return reply.code(403).send({ error: "Avatar non disponible" });
      }

      const imagePath = path.join(
        moduleDir,
        "..",
        "..",
        "private",
        "avatars",
        "animal",
        `${avatarId}.svg`,
      );
      if (!fs.existsSync(imagePath)) {
        return reply.code(404).send({ error: "Image introuvable" });
      }

      const bytes = await fs.promises.readFile(imagePath);
      reply.header("Cache-Control", "private, max-age=3600");
      reply.type("image/svg+xml");
      return reply.send(bytes);
    },
  );

  /**
   * GET /avatars/:avatarId/image
   * Sert l'image d'un avatar si l'utilisateur le possède
   */
  app.get<{
    Params: { avatarId: string };
  }>(
    "/avatars/:avatarId/image",
    { preHandler: requireAuth },
    async (request, reply) => {
      try {
        const avatarId = decodeURIComponent(request.params.avatarId);

        const userId = request.user?.sub;
        if (!userId) {
          return reply.code(401).send({ error: "Authentification requise" });
        }

        // Déterminer le chemin du fichier image
        let imagePath: string;
        let contentType: string;

        // Avatars animaux (1-380) format SVG
        const avatarNumber = parseInt(avatarId, 10);
        if (!isNaN(avatarNumber) && avatarNumber >= 1 && avatarNumber <= 380) {
          // Vérifier si l'utilisateur possède cet avatar (packs + weekly)
          const [rows] = await db.execute(
            `SELECT 1 FROM user_avatars WHERE user_id = ? AND avatar_id = ?
             UNION
             SELECT 1 FROM user_weekly_avatars WHERE user_id = ? AND avatar_id = ?
             LIMIT 1`,
            [userId, avatarNumber, userId, avatarNumber],
          );

          if (!Array.isArray(rows) || rows.length === 0) {
            return reply.code(403).send({ error: "Avatar non possédé" });
          }

          imagePath = path.join(
            moduleDir,
            "..",
            "..",
            "private",
            "avatars",
            "animal",
            `${avatarId}.svg`,
          );
          contentType = "image/svg+xml";
        }
        // Avatars cool (PNG)
        else if (avatarId.startsWith("cool_")) {
          const [rows] = await db.execute(
            "SELECT 1 FROM user_avatar_packs WHERE user_id = ? AND pack_id = 'cool' LIMIT 1",
            [userId],
          );

          if (!Array.isArray(rows) || rows.length === 0) {
            return reply.code(403).send({ error: "Pack avatar non possédé" });
          }

          const filename = avatarId.replace("cool_", "") + ".png";
          imagePath = path.join(
            moduleDir,
            "..",
            "..",
            "private",
            "avatars",
            "cool",
            filename,
          );
          contentType = "image/png";
        }
        // Avatars "récompense" stockés en base (ex: beta-testeur-01)
        else {
          if (avatarId.length > 50) {
            return reply.code(400).send({ error: "Format avatarId invalide" });
          }

          const [rows] = await db.execute(
            `SELECT a.id, a.file_path as filePath
             FROM avatars a
             JOIN user_avatars ua ON ua.avatar_id = a.id
             WHERE ua.user_id = ? AND a.code = ?
             LIMIT 1`,
            [userId, avatarId],
          );

          if (!Array.isArray(rows) || rows.length === 0) {
            return reply.code(403).send({ error: "Avatar non possédé" });
          }

          const row = rows[0] as { filePath?: unknown };
          const rawFilePath =
            typeof row.filePath === "string" ? row.filePath : "";

          // Valider que le chemin est dans un dossier sécurisé autorisé
          const allowedPrefixes = [
            "beta_testeur/",
            "recompense/",
            "evenement/",
          ];
          const isAllowedPath = allowedPrefixes.some((prefix) =>
            rawFilePath.startsWith(prefix),
          );

          if (
            !rawFilePath ||
            !isAllowedPath ||
            rawFilePath.startsWith("/") ||
            rawFilePath.includes("..") ||
            rawFilePath.includes("\\")
          ) {
            return reply.code(500).send({ error: "Chemin avatar invalide" });
          }

          imagePath = path.join(moduleDir, "..", "..", "private", rawFilePath);
          const ext = path.extname(rawFilePath).toLowerCase();
          contentType = ext === ".svg" ? "image/svg+xml" : "image/png";
        }

        if (!fs.existsSync(imagePath)) {
          return reply.code(404).send({ error: "Image introuvable" });
        }

        const bytes = await fs.promises.readFile(imagePath);
        reply.header("Cache-Control", "private, max-age=86400");
        reply.type(contentType);
        return reply.send(bytes);
      } catch (error) {
        request.log.error(
          { err: error, avatarId: request.params.avatarId },
          "avatar_image_failed",
        );
        return reply.code(500).send({ error: "Erreur interne" });
      }
    },
  );
}
