import type { ExtensionAPI, ExtensionContext } from "@jaeswift/jae-coding-agent";
import { existsSync, readFileSync, writeFileSync, mkdirSync } from "node:fs";
import { join } from "node:path";

interface Stats {
  sessionsCount: number;
  totalPrompts: number;
  filesCreated: number;
  filesEdited: number;
  linesWritten: number;
  toolsUsed: number;
  commandsRun: number;
  bugsFixed: number;
  timeSpentMinutes: number;
  fileTypesEdited: Set<string>;
  usedSwarm: boolean;
  usedAllVeniceSkills: boolean;
  longestSessionMinutes: number;
  shortestSessionMinutes: number;
  currentSessionStart: number;
  nightOwlSessions: number;
}

interface Achievement {
  id: string;
  name: string;
  description: string;
  icon: string;
  check: (stats: Stats) => boolean;
}

interface StatsData {
  sessionsCount: number;
  totalPrompts: number;
  filesCreated: number;
  filesEdited: number;
  linesWritten: number;
  toolsUsed: number;
  commandsRun: number;
  bugsFixed: number;
  timeSpentMinutes: number;
  fileTypesEdited: string[];
  usedSwarm: boolean;
  usedAllVeniceSkills: boolean;
  longestSessionMinutes: number;
  shortestSessionMinutes: number;
  nightOwlSessions: number;
  unlockedAchievements: string[];
  personalBests: Record<string, number>;
}

export default function (pi: ExtensionAPI) {
  const configDir = join(process.env.HOME || "/root", ".jae");
  const statsPath = join(configDir, "stats.json");

  const VENICE_SKILLS = [
    "venice-chat", "venice-image-gen", "venice-tts",
    "venice-video-generate", "venice-list-text-models",
    "venice-list-image-models", "venice-list-video-models",
    "venice-chat-benchmark", "venice-video-queue",
    "venice-video-quote", "venice-video-retrieve",
  ];
  const veniceSkillsUsed = new Set<string>();

  const stats: Stats = {
    sessionsCount: 0,
    totalPrompts: 0,
    filesCreated: 0,
    filesEdited: 0,
    linesWritten: 0,
    toolsUsed: 0,
    commandsRun: 0,
    bugsFixed: 0,
    timeSpentMinutes: 0,
    fileTypesEdited: new Set<string>(),
    usedSwarm: false,
    usedAllVeniceSkills: false,
    longestSessionMinutes: 0,
    shortestSessionMinutes: Infinity,
    currentSessionStart: Date.now(),
    nightOwlSessions: 0,
  };

  let unlockedAchievements = new Set<string>();
  let personalBests: Record<string, number> = {};

  const ACHIEVEMENTS: Achievement[] = [
    {
      id: "first_prompt",
      name: "First Prompt",
      description: "Sent your first prompt to JAE",
      icon: "\u{1F476}",
      check: (s) => s.totalPrompts >= 1,
    },
    {
      id: "centurion",
      name: "100 Prompts",
      description: "Sent 100 prompts total",
      icon: "\u{1F4AF}",
      check: (s) => s.totalPrompts >= 100,
    },
    {
      id: "file_creator",
      name: "File Creator",
      description: "Created 10 files",
      icon: "\u{1F4C4}",
      check: (s) => s.filesCreated >= 10,
    },
    {
      id: "bug_squasher",
      name: "Bug Squasher",
      description: "Fixed 10 bugs",
      icon: "\u{1F41B}",
      check: (s) => s.bugsFixed >= 10,
    },
    {
      id: "night_owl",
      name: "Night Owl",
      description: "Coded after midnight",
      icon: "\u{1F989}",
      check: (s) => s.nightOwlSessions >= 1,
    },
    {
      id: "speed_demon",
      name: "Speed Demon",
      description: "Completed a session in under 5 minutes",
      icon: "\u26A1",
      check: (s) => s.shortestSessionMinutes > 0 && s.shortestSessionMinutes < 5,
    },
    {
      id: "marathon",
      name: "Marathon",
      description: "Session lasting over 2 hours",
      icon: "\u{1F3C3}",
      check: (s) => s.longestSessionMinutes >= 120,
    },
    {
      id: "swarm_master",
      name: "Swarm Master",
      description: "Used swarm mode",
      icon: "\u{1F41D}",
      check: (s) => s.usedSwarm,
    },
    {
      id: "dragon_rider",
      name: "Dragon Rider",
      description: "Used all Venice AI skills",
      icon: "\u{1F409}",
      check: (s) => s.usedAllVeniceSkills,
    },
    {
      id: "full_stack",
      name: "Full Stack",
      description: "Edited 5+ different file types",
      icon: "\u{1F4DA}",
      check: (s) => s.fileTypesEdited.size >= 5,
    },
    {
      id: "tool_master",
      name: "Tool Master",
      description: "Used 50 tools in a session",
      icon: "\u{1F6E0}\uFE0F",
      check: (s) => s.toolsUsed >= 50,
    },
    {
      id: "prolific_writer",
      name: "Prolific Writer",
      description: "Written 1000+ lines of code",
      icon: "\u270D\uFE0F",
      check: (s) => s.linesWritten >= 1000,
    },
  ];

  function loadStats(): void {
    try {
      if (existsSync(statsPath)) {
        const data: StatsData = JSON.parse(readFileSync(statsPath, "utf-8"));
        stats.sessionsCount = data.sessionsCount || 0;
        stats.totalPrompts = data.totalPrompts || 0;
        stats.filesCreated = data.filesCreated || 0;
        stats.filesEdited = data.filesEdited || 0;
        stats.linesWritten = data.linesWritten || 0;
        stats.toolsUsed = data.toolsUsed || 0;
        stats.commandsRun = data.commandsRun || 0;
        stats.bugsFixed = data.bugsFixed || 0;
        stats.timeSpentMinutes = data.timeSpentMinutes || 0;
        stats.fileTypesEdited = new Set(data.fileTypesEdited || []);
        stats.usedSwarm = data.usedSwarm || false;
        stats.usedAllVeniceSkills = data.usedAllVeniceSkills || false;
        stats.longestSessionMinutes = data.longestSessionMinutes || 0;
        stats.shortestSessionMinutes = data.shortestSessionMinutes || Infinity;
        stats.nightOwlSessions = data.nightOwlSessions || 0;
        unlockedAchievements = new Set(data.unlockedAchievements || []);
        personalBests = data.personalBests || {};
      }
    } catch { /* ignore */ }
  }

  function saveStats(): void {
    try {
      if (!existsSync(configDir)) mkdirSync(configDir, { recursive: true });
      const data: StatsData = {
        sessionsCount: stats.sessionsCount,
        totalPrompts: stats.totalPrompts,
        filesCreated: stats.filesCreated,
        filesEdited: stats.filesEdited,
        linesWritten: stats.linesWritten,
        toolsUsed: stats.toolsUsed,
        commandsRun: stats.commandsRun,
        bugsFixed: stats.bugsFixed,
        timeSpentMinutes: stats.timeSpentMinutes,
        fileTypesEdited: Array.from(stats.fileTypesEdited),
        usedSwarm: stats.usedSwarm,
        usedAllVeniceSkills: stats.usedAllVeniceSkills,
        longestSessionMinutes: stats.longestSessionMinutes,
        shortestSessionMinutes: stats.shortestSessionMinutes === Infinity ? 0 : stats.shortestSessionMinutes,
        nightOwlSessions: stats.nightOwlSessions,
        unlockedAchievements: Array.from(unlockedAchievements),
        personalBests,
      };
      writeFileSync(statsPath, JSON.stringify(data, null, 2), "utf-8");
    } catch { /* ignore write errors */ }
  }

  function checkAchievements(ctx: ExtensionContext): void {
    for (const achievement of ACHIEVEMENTS) {
      if (!unlockedAchievements.has(achievement.id) && achievement.check(stats)) {
        unlockedAchievements.add(achievement.id);
        ctx.ui.notify(
          `${achievement.icon} Achievement Unlocked!\n\n` +
            `  ${achievement.name}\n` +
            `  ${achievement.description}\n\n` +
            `Total: ${unlockedAchievements.size}/${ACHIEVEMENTS.length} achievements`,
          "info",
        );
        saveStats();
      }
    }
  }

  function updatePersonalBests(): void {
    const sessionMinutes = Math.floor((Date.now() - stats.currentSessionStart) / 60000);
    if (sessionMinutes > (personalBests.longestSession || 0)) {
      personalBests.longestSession = sessionMinutes;
    }
    if (stats.totalPrompts > (personalBests.mostPrompts || 0)) {
      personalBests.mostPrompts = stats.totalPrompts;
    }
    if (stats.filesCreated > (personalBests.mostFilesCreated || 0)) {
      personalBests.mostFilesCreated = stats.filesCreated;
    }
    if (stats.toolsUsed > (personalBests.mostToolsUsed || 0)) {
      personalBests.mostToolsUsed = stats.toolsUsed;
    }
    if (stats.linesWritten > (personalBests.mostLinesWritten || 0)) {
      personalBests.mostLinesWritten = stats.linesWritten;
    }
  }

  function getFileExtension(filepath: string): string {
    const parts = filepath.split(".");
    return parts.length > 1 ? "." + parts[parts.length - 1] : "";
  }

  function renderStatsDashboard(): string {
    const sessionMinutes = Math.floor((Date.now() - stats.currentSessionStart) / 60000);
    const totalHours = (stats.timeSpentMinutes / 60).toFixed(1);
    const bar = '\u2588';
    const dim = '\u2591';

    // Progress bars
    const promptProgress = Math.min(stats.totalPrompts / 100, 1);
    const promptBar = bar.repeat(Math.floor(promptProgress * 20)) + dim.repeat(20 - Math.floor(promptProgress * 20));

    const fileProgress = Math.min(stats.filesCreated / 10, 1);
    const fileBar = bar.repeat(Math.floor(fileProgress * 20)) + dim.repeat(20 - Math.floor(fileProgress * 20));

    const bugProgress = Math.min(stats.bugsFixed / 10, 1);
    const bugBar = bar.repeat(Math.floor(bugProgress * 20)) + dim.repeat(20 - Math.floor(bugProgress * 20));

    const achievementProgress = unlockedAchievements.size / ACHIEVEMENTS.length;
    const achieveBar = bar.repeat(Math.floor(achievementProgress * 20)) + dim.repeat(20 - Math.floor(achievementProgress * 20));

    const lines = [
      `\u{250C}${'\u2500'.repeat(50)}\u{2510}`,
      `\u{2502}  \u{1F4CA} JAE Coding Statistics Dashboard${' '.repeat(16)}\u{2502}`,
      `\u{251C}${'\u2500'.repeat(50)}\u{2524}`,
      `\u{2502}                                                  \u{2502}`,
      `\u{2502}  \u{1F3AE} Sessions:     ${String(stats.sessionsCount).padEnd(8)} \u23F1\uFE0F  This: ${sessionMinutes}m${' '.repeat(Math.max(0, 12 - String(sessionMinutes).length))}\u{2502}`,
      `\u{2502}  \u{1F4AC} Prompts:      ${String(stats.totalPrompts).padEnd(8)} \u{1F4DD} Lines: ${String(stats.linesWritten).padEnd(10)}\u{2502}`,
      `\u{2502}  \u{1F4C4} Created:      ${String(stats.filesCreated).padEnd(8)} \u270F\uFE0F  Edited: ${String(stats.filesEdited).padEnd(9)}\u{2502}`,
      `\u{2502}  \u{1F6E0}\uFE0F  Tools:       ${String(stats.toolsUsed).padEnd(8)} \u{1F41B} Fixes: ${String(stats.bugsFixed).padEnd(10)}\u{2502}`,
      `\u{2502}  \u23F0 Total time:   ${totalHours}h${' '.repeat(Math.max(0, 35 - totalHours.length))}\u{2502}`,
      `\u{2502}                                                  \u{2502}`,
      `\u{251C}${'\u2500'.repeat(50)}\u{2524}`,
      `\u{2502}  Progress to Achievements:${' '.repeat(24)}\u{2502}`,
      `\u{2502}  Prompts [${promptBar}] ${stats.totalPrompts}/100${' '.repeat(Math.max(0, 6 - String(stats.totalPrompts).length))}\u{2502}`,
      `\u{2502}  Files   [${fileBar}] ${stats.filesCreated}/10${' '.repeat(Math.max(0, 7 - String(stats.filesCreated).length))}\u{2502}`,
      `\u{2502}  Bugs    [${bugBar}] ${stats.bugsFixed}/10${' '.repeat(Math.max(0, 7 - String(stats.bugsFixed).length))}\u{2502}`,
      `\u{2502}  Achieve [${achieveBar}] ${unlockedAchievements.size}/${ACHIEVEMENTS.length}${' '.repeat(Math.max(0, 7 - String(unlockedAchievements.size).length))}\u{2502}`,
      `\u{2502}                                                  \u{2502}`,
      `\u{2502}  \u{1F4C2} File types: ${Array.from(stats.fileTypesEdited).slice(0, 8).join(", ") || "none"}${' '.repeat(Math.max(0, 5))}\u{2502}`,
      `\u{2514}${'\u2500'.repeat(50)}\u{2518}`,
    ];

    return lines.join("\n");
  }

  function renderAchievements(): string {
    const lines: string[] = [
      `\u{1F3C6} Achievements (${unlockedAchievements.size}/${ACHIEVEMENTS.length})`,
      `${'\u2500'.repeat(50)}`,
      "",
    ];

    for (const a of ACHIEVEMENTS) {
      const unlocked = unlockedAchievements.has(a.id);
      const status = unlocked ? "\u2705" : "\u{1F512}";
      const icon = unlocked ? a.icon : "\u2753";
      lines.push(`  ${status} ${icon} ${a.name}`);
      lines.push(`     ${unlocked ? a.description : "????"}`);
      lines.push("");
    }

    return lines.join("\n");
  }

  function renderLeaderboard(): string {
    const lines: string[] = [
      `\u{1F3C5} Personal Bests`,
      `${'\u2500'.repeat(40)}`,
      "",
    ];

    const bests: [string, string, number][] = [
      ["\u23F1\uFE0F", "Longest Session", personalBests.longestSession || 0],
      ["\u{1F4AC}", "Most Prompts", personalBests.mostPrompts || 0],
      ["\u{1F4C4}", "Most Files Created", personalBests.mostFilesCreated || 0],
      ["\u{1F6E0}\uFE0F", "Most Tools Used", personalBests.mostToolsUsed || 0],
      ["\u{1F4DD}", "Most Lines Written", personalBests.mostLinesWritten || 0],
    ];

    for (const [icon, label, value] of bests) {
      const unit = label.includes("Session") ? " min" : "";
      lines.push(`  ${icon} ${label}: ${value}${unit}`);
    }

    return lines.join("\n");
  }

  // Load stats on init
  loadStats();

  // Track session start
  pi.on("session_start", async (_event, ctx) => {
    loadStats();
    stats.sessionsCount++;
    stats.currentSessionStart = Date.now();

    // Check for Night Owl
    const hour = new Date().getHours();
    if (hour >= 0 && hour < 5) {
      stats.nightOwlSessions++;
    }

    saveStats();
    checkAchievements(ctx);

    ctx.ui.setFooter(
      "gamification",
      `\u{1F3AE} S:${stats.sessionsCount} P:${stats.totalPrompts} F:${stats.filesCreated} \u{1F41B}:${stats.bugsFixed} \u{1F3C6}:${unlockedAchievements.size}/${ACHIEVEMENTS.length}`,
    );
  });

  // Track prompts
  pi.on("turn_start", async (_event, ctx) => {
    stats.totalPrompts++;
    saveStats();
    checkAchievements(ctx);

    ctx.ui.setFooter(
      "gamification",
      `\u{1F3AE} S:${stats.sessionsCount} P:${stats.totalPrompts} F:${stats.filesCreated} \u{1F41B}:${stats.bugsFixed} \u{1F3C6}:${unlockedAchievements.size}/${ACHIEVEMENTS.length}`,
    );
  });

  // Track tool calls and file operations
  pi.on("tool_execution_end", async (event, ctx) => {
    stats.toolsUsed++;
    const toolName = event.toolName || "";

    // Track file creates/edits
    if (["write", "write_file"].includes(toolName)) {
      stats.filesCreated++;
      const filePath = (event.input as any)?.path || (event.input as any)?.file_path || "";
      if (filePath) {
        const ext = getFileExtension(filePath);
        if (ext) stats.fileTypesEdited.add(ext);
      }
      // Estimate lines written
      const content = (event.input as any)?.content || "";
      if (typeof content === "string") {
        stats.linesWritten += content.split("\n").length;
      }
    }

    if (["edit", "edit_file"].includes(toolName)) {
      stats.filesEdited++;
      const filePath = (event.input as any)?.path || (event.input as any)?.file_path || "";
      if (filePath) {
        const ext = getFileExtension(filePath);
        if (ext) stats.fileTypesEdited.add(ext);
      }
    }

    if (toolName === "bash" || toolName === "terminal") {
      stats.commandsRun++;
    }

    // Track swarm usage
    if (toolName === "swarm_task") {
      stats.usedSwarm = true;
    }

    // Track Venice skill usage
    if (VENICE_SKILLS.includes(toolName)) {
      veniceSkillsUsed.add(toolName);
      if (veniceSkillsUsed.size >= VENICE_SKILLS.length) {
        stats.usedAllVeniceSkills = true;
      }
    }

    saveStats();
    checkAchievements(ctx);
  });

  // Track bug fixes via agent messages
  pi.on("agent_end", async (event, ctx) => {
    // Check messages for bug fix indicators
    for (const message of event.messages) {
      if (message && typeof message === "object" && "content" in message) {
        const content = typeof (message as any).content === "string" ? (message as any).content : "";
        const fixPatterns = ["fixed", "bug fix", "resolved", "patched", "corrected the error", "fixed the issue", "fixed the bug"];
        const lowerContent = content.toLowerCase();
        for (const pattern of fixPatterns) {
          if (lowerContent.includes(pattern)) {
            stats.bugsFixed++;
            break;
          }
        }
      }
    }

    // Update session time
    const sessionMinutes = Math.floor((Date.now() - stats.currentSessionStart) / 60000);
    stats.timeSpentMinutes += 1; // Increment per agent_end call
    if (sessionMinutes > stats.longestSessionMinutes) {
      stats.longestSessionMinutes = sessionMinutes;
    }
    if (sessionMinutes > 0 && sessionMinutes < stats.shortestSessionMinutes) {
      stats.shortestSessionMinutes = sessionMinutes;
    }

    updatePersonalBests();
    saveStats();
    checkAchievements(ctx);
  });

  pi.registerCommand("stats", {
    description: "Show coding statistics dashboard",
    handler: async (_args, ctx) => {
      loadStats();
      const dashboard = renderStatsDashboard();
      ctx.ui.notify(dashboard, "info");
    },
  });

  pi.registerCommand("achievements", {
    description: "Show unlocked achievements",
    handler: async (_args, ctx) => {
      loadStats();
      const achievements = renderAchievements();
      ctx.ui.notify(achievements, "info");
    },
  });

  pi.registerCommand("leaderboard", {
    description: "Show personal bests",
    handler: async (_args, ctx) => {
      loadStats();
      const leaderboard = renderLeaderboard();
      ctx.ui.notify(leaderboard, "info");
    },
  });
}
