import { describe, it, expect, vi, beforeEach } from "vitest";
import type { RouterContextProvider } from "react-router";
import { action } from "~/routes/api/autodraft.update";

const ctx = {} as unknown as RouterContextProvider;

// Mock dependencies
vi.mock("~/database/context");
vi.mock("~/server/socket", () => ({
  getSocketIO: vi.fn(),
}));
vi.mock("@clerk/react-router/server", () => ({
  getAuth: vi.fn(),
}));
vi.mock("~/models/user", () => ({
  isUserAdminByClerkId: vi.fn().mockResolvedValue(false),
}));

describe("Autodraft Settings API", () => {
  let mockDb: any;
  let mockSocketIO: any;

  beforeEach(async () => {
    vi.clearAllMocks();

    // Mock Clerk auth
    const { getAuth } = await import("@clerk/react-router/server");
    vi.mocked(getAuth).mockResolvedValue({ userId: "user-789" } as any);

    // Mock Socket.IO
    mockSocketIO = {
      to: vi.fn().mockReturnThis(),
      emit: vi.fn(),
    };

    const socketModule = await import("~/server/socket");
    vi.mocked(socketModule.getSocketIO).mockReturnValue(mockSocketIO);

    // Mock database
    mockDb = {
      query: {
        teams: {
          findFirst: vi.fn(),
        },
        seasons: {
          findFirst: vi.fn().mockResolvedValue({ id: "season-123", leagueId: "league-1" }),
        },
        commissioners: {
          findFirst: vi.fn().mockResolvedValue(null),
        },
        autodraftSettings: {
          findFirst: vi.fn(),
        },
      },
      update: vi.fn().mockReturnThis(),
      set: vi.fn().mockReturnThis(),
      where: vi.fn().mockReturnThis(),
      returning: vi.fn(),
      insert: vi.fn().mockReturnThis(),
      values: vi.fn().mockReturnThis(),
    };

    const { database } = await import("~/database/context");
    vi.mocked(database).mockReturnValue(mockDb);
  });

  describe("Update Autodraft Settings", () => {
    it("should create new autodraft settings when none exist", async () => {
      const seasonId = "season-123";
      const teamId = "team-456";
      const userId = "user-789";

      // Mock team ownership verification
      mockDb.query.teams.findFirst.mockResolvedValue({
        id: teamId,
        ownerId: userId,
        name: "Test Team",
      });

      // Mock no existing settings
      mockDb.query.autodraftSettings.findFirst.mockResolvedValue(null);

      // Mock insert returning new settings
      const newSettings = {
        id: "settings-1",
        seasonId,
        teamId,
        isEnabled: true,
        mode: "next_pick",
        queueOnly: false,
        createdAt: new Date(),
        updatedAt: new Date(),
      };
      mockDb.returning.mockResolvedValue([newSettings]);

      const formData = new FormData();
      formData.append("seasonId", seasonId);
      formData.append("teamId", teamId);
      formData.append("isEnabled", "true");
      formData.append("mode", "next_pick");
      formData.append("queueOnly", "false");

      const request = new Request("http://localhost/api/autodraft/update", {
        method: "POST",
        body: formData,
      });

      const response = await action({
        request,
        params: {},
        context: ctx,
      });

      const data = await response.json();

      expect(data.success).toBe(true);
      expect(data.settings.id).toBe(newSettings.id);
      expect(data.settings.isEnabled).toBe(true);
      expect(data.settings.mode).toBe("next_pick");
      expect(mockDb.insert).toHaveBeenCalled();
      expect(mockSocketIO.to).toHaveBeenCalledWith(`draft-${seasonId}`);
      expect(mockSocketIO.emit).toHaveBeenCalledWith("autodraft-updated", {
        teamId,
        isEnabled: true,
        mode: "next_pick",
        queueOnly: false,
        source: "user",
      });
    });

    it("should update existing autodraft settings", async () => {
      const seasonId = "season-123";
      const teamId = "team-456";
      const userId = "user-789";

      mockDb.query.teams.findFirst.mockResolvedValue({
        id: teamId,
        ownerId: userId,
        name: "Test Team",
      });

      const existingSettings = {
        id: "settings-1",
        seasonId,
        teamId,
        isEnabled: false,
        mode: "next_pick",
        queueOnly: false,
        createdAt: new Date(),
        updatedAt: new Date(),
      };
      mockDb.query.autodraftSettings.findFirst.mockResolvedValue(existingSettings);

      const updatedSettings = {
        ...existingSettings,
        isEnabled: true,
        mode: "while_on",
        queueOnly: false,
        updatedAt: new Date(),
      };
      mockDb.returning.mockResolvedValue([updatedSettings]);

      const formData = new FormData();
      formData.append("seasonId", seasonId);
      formData.append("teamId", teamId);
      formData.append("isEnabled", "true");
      formData.append("mode", "while_on");
      formData.append("queueOnly", "false");

      const request = new Request("http://localhost/api/autodraft/update", {
        method: "POST",
        body: formData,
      });

      const response = await action({
        request,
        params: {},
        context: ctx,
      });

      const data = await response.json();

      expect(data.success).toBe(true);
      expect(data.settings.isEnabled).toBe(true);
      expect(data.settings.mode).toBe("while_on");
      expect(mockDb.update).toHaveBeenCalled();
      expect(mockSocketIO.emit).toHaveBeenCalledWith("autodraft-updated", {
        teamId,
        isEnabled: true,
        mode: "while_on",
        queueOnly: false,
        source: "user",
      });
    });

    it("should save queueOnly flag correctly", async () => {
      const seasonId = "season-123";
      const teamId = "team-456";
      const userId = "user-789";

      mockDb.query.teams.findFirst.mockResolvedValue({
        id: teamId,
        ownerId: userId,
        name: "Test Team",
      });
      mockDb.query.autodraftSettings.findFirst.mockResolvedValue(null);

      const newSettings = {
        id: "settings-1",
        seasonId,
        teamId,
        isEnabled: true,
        mode: "next_pick",
        queueOnly: true,
        createdAt: new Date(),
        updatedAt: new Date(),
      };
      mockDb.returning.mockResolvedValue([newSettings]);

      const formData = new FormData();
      formData.append("seasonId", seasonId);
      formData.append("teamId", teamId);
      formData.append("isEnabled", "true");
      formData.append("mode", "next_pick");
      formData.append("queueOnly", "true");

      const request = new Request("http://localhost/api/autodraft/update", {
        method: "POST",
        body: formData,
      });

      const response = await action({
        request,
        params: {},
        context: ctx,
      });

      const data = await response.json();

      expect(data.success).toBe(true);
      expect(data.settings.queueOnly).toBe(true);
      expect(mockSocketIO.emit).toHaveBeenCalledWith("autodraft-updated", {
        teamId,
        isEnabled: true,
        mode: "next_pick",
        queueOnly: true,
        source: "user",
      });
    });

    it("should reject unauthorized users", async () => {
      const seasonId = "season-123";
      const teamId = "team-456";
      const differentUserId = "user-999";

      mockDb.query.teams.findFirst.mockResolvedValue({
        id: teamId,
        ownerId: differentUserId,
        name: "Test Team",
      });

      const formData = new FormData();
      formData.append("seasonId", seasonId);
      formData.append("teamId", teamId);
      formData.append("isEnabled", "true");
      formData.append("mode", "next_pick");

      const request = new Request("http://localhost/api/autodraft/update", {
        method: "POST",
        body: formData,
      });

      const response = await action({
        request,
        params: {},
        context: ctx,
      });

      expect(response.status).toBe(403);
      const data = await response.json();
      expect(data.error).toBe("Unauthorized");
    });

    it("should require all fields", async () => {
      const formData = new FormData();
      formData.append("seasonId", "season-123");
      // Missing teamId and mode

      const request = new Request("http://localhost/api/autodraft/update", {
        method: "POST",
        body: formData,
      });

      const response = await action({
        request,
        params: {},
        context: ctx,
      });

      expect(response.status).toBe(400);
      const data = await response.json();
      expect(data.error).toBe("Missing required fields");
    });

    it("should handle all three autodraft states (Off, Next Pick, All Picks)", async () => {
      const seasonId = "season-123";
      const teamId = "team-456";
      const userId = "user-789";

      mockDb.query.teams.findFirst.mockResolvedValue({
        id: teamId,
        ownerId: userId,
        name: "Test Team",
      });

      mockDb.query.autodraftSettings.findFirst.mockResolvedValue(null);

      // State 1: Off (isEnabled=false)
      const offSettings = {
        id: "settings-1",
        seasonId,
        teamId,
        isEnabled: false,
        mode: "next_pick",
        queueOnly: false,
        createdAt: new Date(),
        updatedAt: new Date(),
      };
      mockDb.returning.mockResolvedValueOnce([offSettings]);

      const formData1 = new FormData();
      formData1.append("seasonId", seasonId);
      formData1.append("teamId", teamId);
      formData1.append("isEnabled", "false");
      formData1.append("mode", "next_pick");
      formData1.append("queueOnly", "false");

      const response1 = await action({
        request: new Request("http://localhost/api/autodraft/update", { method: "POST", body: formData1 }),
        params: {},
        context: ctx,
      });
      const data1 = await response1.json();
      expect(data1.settings.isEnabled).toBe(false);

      // State 2: Next Pick (isEnabled=true, mode=next_pick)
      const nextPickSettings = { ...offSettings, id: "settings-2", isEnabled: true, mode: "next_pick" };
      mockDb.returning.mockResolvedValueOnce([nextPickSettings]);

      const formData2 = new FormData();
      formData2.append("seasonId", seasonId);
      formData2.append("teamId", teamId);
      formData2.append("isEnabled", "true");
      formData2.append("mode", "next_pick");
      formData2.append("queueOnly", "false");

      const response2 = await action({
        request: new Request("http://localhost/api/autodraft/update", { method: "POST", body: formData2 }),
        params: {},
        context: ctx,
      });
      const data2 = await response2.json();
      expect(data2.settings.isEnabled).toBe(true);
      expect(data2.settings.mode).toBe("next_pick");

      // State 3: All Picks (isEnabled=true, mode=while_on)
      const allPicksSettings = { ...offSettings, id: "settings-3", isEnabled: true, mode: "while_on" };
      mockDb.returning.mockResolvedValueOnce([allPicksSettings]);

      const formData3 = new FormData();
      formData3.append("seasonId", seasonId);
      formData3.append("teamId", teamId);
      formData3.append("isEnabled", "true");
      formData3.append("mode", "while_on");
      formData3.append("queueOnly", "false");

      const response3 = await action({
        request: new Request("http://localhost/api/autodraft/update", { method: "POST", body: formData3 }),
        params: {},
        context: ctx,
      });
      const data3 = await response3.json();
      expect(data3.settings.isEnabled).toBe(true);
      expect(data3.settings.mode).toBe("while_on");
    });

    it("should emit socket event to correct room with queueOnly included", async () => {
      const seasonId = "season-abc";
      const teamId = "team-xyz";
      const userId = "user-123";

      const { getAuth } = await import("@clerk/react-router/server");
      vi.mocked(getAuth).mockResolvedValue({ userId } as any);

      mockDb.query.teams.findFirst.mockResolvedValue({
        id: teamId,
        ownerId: userId,
        name: "Test Team",
      });

      mockDb.query.autodraftSettings.findFirst.mockResolvedValue(null);

      mockDb.returning.mockResolvedValue([{
        id: "settings-1",
        seasonId,
        teamId,
        isEnabled: true,
        mode: "next_pick",
        queueOnly: true,
        createdAt: new Date(),
        updatedAt: new Date(),
      }]);

      const formData = new FormData();
      formData.append("seasonId", seasonId);
      formData.append("teamId", teamId);
      formData.append("isEnabled", "true");
      formData.append("mode", "next_pick");
      formData.append("queueOnly", "true");

      await action({
        request: new Request("http://localhost/api/autodraft/update", { method: "POST", body: formData }),
        params: {},
        context: ctx,
      });

      expect(mockSocketIO.to).toHaveBeenCalledWith(`draft-${seasonId}`);
      expect(mockSocketIO.emit).toHaveBeenCalledWith("autodraft-updated", {
        teamId,
        isEnabled: true,
        mode: "next_pick",
        queueOnly: true,
        source: "user",
      });
    });
  });
});
