import { describe, it, expect, beforeEach, vi } from "vitest";
import { get } from "svelte/store";
import { stats, formattedStats, resetSessionStats } from "./stats";
import type { UsageStats } from "./stats";

// Mock Tauri APIs
vi.mock("@tauri-apps/api/event", () => ({
  listen: vi.fn(),
}));

vi.mock("@tauri-apps/api/core", () => ({
  invoke: vi.fn(),
}));

describe("stats store", () => {
  beforeEach(() => {
    // Reset stats to default before each test
    stats.set({
      total_input_tokens: 0,
      total_output_tokens: 0,
      total_cost_usd: 0,
      session_input_tokens: 0,
      session_output_tokens: 0,
      session_cost_usd: 0,
      model: null,
      messages_exchanged: 0,
      session_messages_exchanged: 0,
      code_blocks_generated: 0,
      session_code_blocks_generated: 0,
      files_edited: 0,
      session_files_edited: 0,
      files_created: 0,
      session_files_created: 0,
      tools_usage: {},
      session_tools_usage: {},
      session_duration_seconds: 0,
    });
  });

  describe("stats writable store", () => {
    it("has correct default values", () => {
      const currentStats = get(stats);
      expect(currentStats.total_input_tokens).toBe(0);
      expect(currentStats.total_output_tokens).toBe(0);
      expect(currentStats.total_cost_usd).toBe(0);
      expect(currentStats.model).toBeNull();
    });

    it("can be updated with set", () => {
      const newStats: UsageStats = {
        total_input_tokens: 1000,
        total_output_tokens: 2000,
        total_cost_usd: 0.05,
        session_input_tokens: 500,
        session_output_tokens: 1000,
        session_cost_usd: 0.025,
        model: "claude-sonnet-4",
        messages_exchanged: 10,
        session_messages_exchanged: 5,
        code_blocks_generated: 3,
        session_code_blocks_generated: 2,
        files_edited: 5,
        session_files_edited: 2,
        files_created: 1,
        session_files_created: 1,
        tools_usage: { Read: 5, Edit: 3 },
        session_tools_usage: { Read: 2, Edit: 1 },
        session_duration_seconds: 300,
      };

      stats.set(newStats);
      const currentStats = get(stats);

      expect(currentStats.total_input_tokens).toBe(1000);
      expect(currentStats.total_output_tokens).toBe(2000);
      expect(currentStats.model).toBe("claude-sonnet-4");
      expect(currentStats.tools_usage).toEqual({ Read: 5, Edit: 3 });
    });

    it("can be updated with update function", () => {
      stats.update((current) => ({
        ...current,
        total_input_tokens: 500,
        session_messages_exchanged: 3,
      }));

      const currentStats = get(stats);
      expect(currentStats.total_input_tokens).toBe(500);
      expect(currentStats.session_messages_exchanged).toBe(3);
    });
  });

  describe("resetSessionStats", () => {
    it("resets all session fields to zero", () => {
      // First set some values
      stats.set({
        total_input_tokens: 1000,
        total_output_tokens: 2000,
        total_cost_usd: 0.05,
        session_input_tokens: 500,
        session_output_tokens: 1000,
        session_cost_usd: 0.025,
        model: "claude-sonnet-4",
        messages_exchanged: 10,
        session_messages_exchanged: 5,
        code_blocks_generated: 3,
        session_code_blocks_generated: 2,
        files_edited: 5,
        session_files_edited: 2,
        files_created: 1,
        session_files_created: 1,
        tools_usage: { Read: 5, Edit: 3 },
        session_tools_usage: { Read: 2, Edit: 1 },
        session_duration_seconds: 300,
      });

      // Reset session stats
      resetSessionStats();

      const currentStats = get(stats);

      // Total stats should be preserved
      expect(currentStats.total_input_tokens).toBe(1000);
      expect(currentStats.total_output_tokens).toBe(2000);
      expect(currentStats.total_cost_usd).toBe(0.05);
      expect(currentStats.messages_exchanged).toBe(10);
      expect(currentStats.code_blocks_generated).toBe(3);
      expect(currentStats.files_edited).toBe(5);
      expect(currentStats.files_created).toBe(1);
      expect(currentStats.tools_usage).toEqual({ Read: 5, Edit: 3 });
      expect(currentStats.model).toBe("claude-sonnet-4");

      // Session stats should be reset
      expect(currentStats.session_input_tokens).toBe(0);
      expect(currentStats.session_output_tokens).toBe(0);
      expect(currentStats.session_cost_usd).toBe(0);
      expect(currentStats.session_messages_exchanged).toBe(0);
      expect(currentStats.session_code_blocks_generated).toBe(0);
      expect(currentStats.session_files_edited).toBe(0);
      expect(currentStats.session_files_created).toBe(0);
      expect(currentStats.session_tools_usage).toEqual({});
      expect(currentStats.session_duration_seconds).toBe(0);
    });
  });

  describe("formattedStats derived store", () => {
    it("formats token numbers with locale string", () => {
      stats.update((current) => ({
        ...current,
        total_input_tokens: 1234567,
        total_output_tokens: 7654321,
        session_input_tokens: 12345,
        session_output_tokens: 54321,
      }));

      const formatted = get(formattedStats);

      expect(formatted.totalTokens).toBe("8,888,888");
      expect(formatted.totalInputTokens).toBe("1,234,567");
      expect(formatted.totalOutputTokens).toBe("7,654,321");
      expect(formatted.sessionTokens).toBe("66,666");
      expect(formatted.sessionInputTokens).toBe("12,345");
      expect(formatted.sessionOutputTokens).toBe("54,321");
    });

    it("formats cost with 4 decimal places", () => {
      stats.update((current) => ({
        ...current,
        total_cost_usd: 1.23456,
        session_cost_usd: 0.00123,
      }));

      const formatted = get(formattedStats);

      expect(formatted.totalCost).toBe("$1.2346");
      expect(formatted.sessionCost).toBe("$0.0012");
    });

    it("formats duration seconds only", () => {
      stats.update((current) => ({
        ...current,
        session_duration_seconds: 45,
      }));

      const formatted = get(formattedStats);
      expect(formatted.sessionDuration).toBe("45s");
    });

    it("formats duration minutes and seconds", () => {
      stats.update((current) => ({
        ...current,
        session_duration_seconds: 125, // 2m 5s
      }));

      const formatted = get(formattedStats);
      expect(formatted.sessionDuration).toBe("2m 5s");
    });

    it("formats duration hours, minutes, and seconds", () => {
      stats.update((current) => ({
        ...current,
        session_duration_seconds: 3725, // 1h 2m 5s
      }));

      const formatted = get(formattedStats);
      expect(formatted.sessionDuration).toBe("1h 2m 5s");
    });

    it("formats duration with zero seconds", () => {
      stats.update((current) => ({
        ...current,
        session_duration_seconds: 3600, // exactly 1h
      }));

      const formatted = get(formattedStats);
      expect(formatted.sessionDuration).toBe("1h 0m 0s");
    });

    it("shows model name when available", () => {
      stats.update((current) => ({
        ...current,
        model: "claude-opus-4-5",
      }));

      const formatted = get(formattedStats);
      expect(formatted.model).toBe("claude-opus-4-5");
    });

    it("shows placeholder when model is null", () => {
      stats.update((current) => ({
        ...current,
        model: null,
      }));

      const formatted = get(formattedStats);
      expect(formatted.model).toBe("No model selected");
    });

    it("formats message counts", () => {
      stats.update((current) => ({
        ...current,
        messages_exchanged: 100,
        session_messages_exchanged: 10,
      }));

      const formatted = get(formattedStats);
      expect(formatted.messagesTotal).toBe("100");
      expect(formatted.messagesSession).toBe("10");
    });

    it("formats code block counts", () => {
      stats.update((current) => ({
        ...current,
        code_blocks_generated: 50,
        session_code_blocks_generated: 5,
      }));

      const formatted = get(formattedStats);
      expect(formatted.codeBlocksTotal).toBe("50");
      expect(formatted.codeBlocksSession).toBe("5");
    });

    it("formats file counts", () => {
      stats.update((current) => ({
        ...current,
        files_edited: 25,
        session_files_edited: 3,
        files_created: 10,
        session_files_created: 2,
      }));

      const formatted = get(formattedStats);
      expect(formatted.filesEditedTotal).toBe("25");
      expect(formatted.filesEditedSession).toBe("3");
      expect(formatted.filesCreatedTotal).toBe("10");
      expect(formatted.filesCreatedSession).toBe("2");
    });

    it("exposes tools usage directly", () => {
      const toolsUsage = { Read: 10, Edit: 5, Write: 3 };
      const sessionToolsUsage = { Read: 2, Edit: 1 };

      stats.update((current) => ({
        ...current,
        tools_usage: toolsUsage,
        session_tools_usage: sessionToolsUsage,
      }));

      const formatted = get(formattedStats);
      expect(formatted.toolsUsage).toEqual(toolsUsage);
      expect(formatted.sessionToolsUsage).toEqual(sessionToolsUsage);
    });

    it("handles zero values correctly", () => {
      const formatted = get(formattedStats);

      expect(formatted.totalTokens).toBe("0");
      expect(formatted.totalCost).toBe("$0.0000");
      expect(formatted.sessionDuration).toBe("0s");
      expect(formatted.messagesTotal).toBe("0");
    });

    it("handles large numbers with proper formatting", () => {
      stats.update((current) => ({
        ...current,
        total_input_tokens: 1000000000, // 1 billion
        messages_exchanged: 999999,
      }));

      const formatted = get(formattedStats);
      expect(formatted.totalInputTokens).toBe("1,000,000,000");
      expect(formatted.messagesTotal).toBe("999,999");
    });
  });

  describe("UsageStats interface", () => {
    it("supports all expected fields", () => {
      const fullStats: UsageStats = {
        total_input_tokens: 100,
        total_output_tokens: 200,
        total_cost_usd: 0.01,
        session_input_tokens: 50,
        session_output_tokens: 100,
        session_cost_usd: 0.005,
        model: "test-model",
        messages_exchanged: 5,
        session_messages_exchanged: 2,
        code_blocks_generated: 3,
        session_code_blocks_generated: 1,
        files_edited: 2,
        session_files_edited: 1,
        files_created: 1,
        session_files_created: 0,
        tools_usage: { Read: 3 },
        session_tools_usage: { Read: 1 },
        session_duration_seconds: 60,
      };

      stats.set(fullStats);
      const currentStats = get(stats);

      // Verify all fields are present and correct
      expect(currentStats).toEqual(fullStats);
    });
  });
});
