import { describe, it, expect, beforeEach, vi } from "vitest";
import {
  executeAutomatedActions,
  isAccountSuspended,
  areWithdrawalsHeld,
  getAccountRestrictions,
} from "./fraudActions.ts";

// Mock database with wallet data
vi.mock("../db", () => {
  const mockWallet = {
    userId: 123,
    gcBalance: "1000.00",
    scBalance: "5000.00",
    maxGcBetLimit: "100.00",
    maxScBetLimit: "500.00",
  };

  return {
    getDb: vi.fn(() =>
      Promise.resolve({
        select: vi.fn().mockReturnValue({
          from: vi.fn().mockReturnValue({
            where: vi.fn().mockReturnValue({
              limit: vi.fn().mockResolvedValue([mockWallet]),
              orderBy: vi.fn().mockReturnValue({
                limit: vi.fn().mockResolvedValue([]),
              }),
            }),
          }),
        }),
        update: vi.fn().mockReturnValue({
          set: vi.fn().mockReturnValue({
            where: vi.fn().mockResolvedValue({}),
          }),
        }),
        insert: vi.fn().mockReturnValue({
          values: vi.fn().mockResolvedValue({}),
        }),
      })
    ),
    writeAuditLog: vi.fn().mockResolvedValue({}),
  };
});

// Mock notification
vi.mock("../_core/notification", () => ({
  notifyOwner: vi.fn().mockResolvedValue(true),
}));

describe("Fraud Actions Service", () => {
  beforeEach(() => {
    vi.clearAllMocks();
  });

  describe("executeAutomatedActions", () => {
    it("should execute critical actions for critical alerts", async () => {
      const results = await executeAutomatedActions(123, 1, "critical", "rapid_betting");

      expect(results).toBeDefined();
      expect(Array.isArray(results)).toBe(true);
      expect(results.length).toBeGreaterThan(0);
    });

    it("should execute high actions for high alerts", async () => {
      const results = await executeAutomatedActions(123, 1, "high", "velocity");

      expect(results).toBeDefined();
      expect(Array.isArray(results)).toBe(true);
      expect(results.length).toBeGreaterThan(0);
    });

    it("should execute medium actions for medium alerts", async () => {
      const results = await executeAutomatedActions(123, 1, "medium", "abnormal_rtp");

      expect(results).toBeDefined();
      expect(Array.isArray(results)).toBe(true);
    });

    it("should not execute actions for low alerts", async () => {
      const results = await executeAutomatedActions(123, 1, "low", "pattern");

      expect(results).toBeDefined();
      expect(Array.isArray(results)).toBe(true);
      expect(results.length).toBe(0);
    });

    it("should include action details in results", async () => {
      const results = await executeAutomatedActions(123, 1, "critical", "rapid_betting");

      if (results.length > 0) {
        const result = results[0];
        expect(result).toHaveProperty("success");
        expect(result).toHaveProperty("action");
        expect(result).toHaveProperty("message");
        expect(result).toHaveProperty("details");

        expect(result.action).toHaveProperty("type");
        expect(result.action).toHaveProperty("userId", 123);
        expect(result.action).toHaveProperty("alertId", 1);
      }
    });
  });

  describe("isAccountSuspended", () => {
    it("should return false for non-suspended account", async () => {
      const suspended = await isAccountSuspended(123);
      expect(suspended).toBe(false);
    });

    it("should handle missing user", async () => {
      const suspended = await isAccountSuspended(999);
      expect(suspended).toBe(false);
    });
  });

  describe("areWithdrawalsHeld", () => {
    it("should return false for account without hold", async () => {
      const held = await areWithdrawalsHeld(123);
      expect(held).toBe(false);
    });

    it("should handle missing user", async () => {
      const held = await areWithdrawalsHeld(999);
      expect(held).toBe(false);
    });
  });

  describe("getAccountRestrictions", () => {
    it("should return default restrictions for clean account", async () => {
      const restrictions = await getAccountRestrictions(123);

      expect(restrictions).toHaveProperty("suspended", false);
      expect(restrictions).toHaveProperty("withdrawalsHeld", false);
      expect(restrictions).toHaveProperty("betLimited", false);
      expect(restrictions).toHaveProperty("flagged", false);
      expect(restrictions).toHaveProperty("restrictions");
      expect(Array.isArray(restrictions.restrictions)).toBe(true);
    });

    it("should return empty restrictions array for clean account", async () => {
      const restrictions = await getAccountRestrictions(123);
      expect(restrictions.restrictions).toHaveLength(0);
    });

    it("should handle database unavailable", async () => {
      const { getDb } = await import("../db");
      vi.mocked(getDb).mockResolvedValueOnce(null);

      const restrictions = await getAccountRestrictions(123);

      expect(restrictions.suspended).toBe(false);
      expect(restrictions.withdrawalsHeld).toBe(false);
      expect(restrictions.restrictions).toHaveLength(0);
    });
  });

  describe("Action Types", () => {
    it("should create suspension action with correct structure", async () => {
      const results = await executeAutomatedActions(123, 1, "critical", "rapid_betting");

      const suspensionAction = results.find((r) => r.action.type === "suspend_account");
      if (suspensionAction) {
        expect(suspensionAction.action.type).toBe("suspend_account");
        expect(suspensionAction.action.userId).toBe(123);
        expect(suspensionAction.action.alertId).toBe(1);
        expect(suspensionAction.action.executedBy).toBe("system");
        expect(suspensionAction.details).toHaveProperty("suspensionUntil");
      }
    });

    it("should create hold withdrawal action with correct structure", async () => {
      const results = await executeAutomatedActions(123, 1, "critical", "rapid_betting");

      const holdAction = results.find((r) => r.action.type === "hold_withdrawal");
      if (holdAction) {
        expect(holdAction.action.type).toBe("hold_withdrawal");
        expect(holdAction.details).toHaveProperty("holdUntil");
      }
    });

    it("should create flag account action with correct structure", async () => {
      const results = await executeAutomatedActions(123, 1, "high", "velocity");

      const flagAction = results.find((r) => r.action.type === "flag_account");
      if (flagAction) {
        expect(flagAction.action.type).toBe("flag_account");
        expect(flagAction.details).toHaveProperty("flagged", true);
      }
    });
  });

  describe("Error Handling", () => {
    it("should handle database unavailable", async () => {
      const { getDb } = await import("../db");
      vi.mocked(getDb).mockResolvedValueOnce(null);

      await expect(executeAutomatedActions(123, 1, "critical", "rapid_betting")).rejects.toThrow(
        "Database unavailable"
      );
    });

    it("should handle invalid alert type", async () => {
      const results = await executeAutomatedActions(123, 1, "critical", "invalid_type" as any);

      expect(results).toBeDefined();
      expect(Array.isArray(results)).toBe(true);
    });
  });

  describe("Risk Severity Mapping", () => {
    it("should execute 3 actions for critical severity", async () => {
      const results = await executeAutomatedActions(123, 1, "critical", "rapid_betting");

      expect(results.length).toBeGreaterThanOrEqual(1);
    });

    it("should execute 2 actions for high severity", async () => {
      const results = await executeAutomatedActions(123, 1, "high", "velocity");

      expect(results.length).toBeGreaterThanOrEqual(1);
    });

    it("should execute 1 action for medium severity", async () => {
      const results = await executeAutomatedActions(123, 1, "medium", "abnormal_rtp");

      expect(results.length).toBeGreaterThanOrEqual(0);
    });
  });
});
