/**
 * Tests for Settings component.
 *
 * TDD: These tests define the expected behavior before implementation.
 */

import { describe, it, expect, vi, beforeEach } from "vitest";
import { render, screen, waitFor } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { Settings } from "@/components/Settings";
import type { SettingsData } from "@/components/Settings";

const defaultSettings: SettingsData = {
  schemaVersion: 1,
  hotkeys: {
    toggle: "Meta+Shift+M",
    capture: "Meta+Shift+C",
  },
  lorePath: null,
  reconciliationHours: 6,
  floatingWidget: false,
  defaultDefer: "1h",
  sounds: true,
  theme: "dark",
  notifications: true,
};

describe("Settings", () => {
  beforeEach(() => {
    vi.clearAllMocks();
  });

  describe("loading state", () => {
    it("displays current settings on mount", () => {
      render(<Settings settings={defaultSettings} onSave={vi.fn()} />);

      // Check hotkey displays
      expect(screen.getByDisplayValue("Meta+Shift+M")).toBeInTheDocument();
      expect(screen.getByDisplayValue("Meta+Shift+C")).toBeInTheDocument();
    });

    it("shows data directory info", () => {
      render(
        <Settings
          settings={defaultSettings}
          onSave={vi.fn()}
          dataDir="~/.local/share/mc"
        />
      );

      expect(screen.getByText(/\.local\/share\/mc/)).toBeInTheDocument();
    });
  });

  describe("theme toggle", () => {
    it("renders theme toggle with current value", () => {
      render(<Settings settings={defaultSettings} onSave={vi.fn()} />);

      const themeToggle = screen.getByRole("switch", { name: /dark mode/i });
      expect(themeToggle).toBeChecked();
    });

    it("calls onSave when theme is toggled", async () => {
      const user = userEvent.setup();
      const onSave = vi.fn();
      render(<Settings settings={defaultSettings} onSave={onSave} />);

      const themeToggle = screen.getByRole("switch", { name: /dark mode/i });
      await user.click(themeToggle);

      expect(onSave).toHaveBeenCalledWith(
        expect.objectContaining({
          theme: "light",
        })
      );
    });
  });

  describe("notification preferences", () => {
    it("renders notification toggle", () => {
      render(<Settings settings={defaultSettings} onSave={vi.fn()} />);

      const notifToggle = screen.getByRole("switch", { name: /notifications/i });
      expect(notifToggle).toBeChecked();
    });

    it("calls onSave when notifications toggled", async () => {
      const user = userEvent.setup();
      const onSave = vi.fn();
      render(<Settings settings={defaultSettings} onSave={onSave} />);

      const notifToggle = screen.getByRole("switch", { name: /notifications/i });
      await user.click(notifToggle);

      expect(onSave).toHaveBeenCalledWith(
        expect.objectContaining({
          notifications: false,
        })
      );
    });
  });

  describe("sound effects", () => {
    it("renders sound effects toggle", () => {
      render(<Settings settings={defaultSettings} onSave={vi.fn()} />);

      const soundToggle = screen.getByRole("switch", { name: /sound effects/i });
      expect(soundToggle).toBeChecked();
    });

    it("calls onSave when sound effects toggled", async () => {
      const user = userEvent.setup();
      const onSave = vi.fn();
      render(<Settings settings={defaultSettings} onSave={onSave} />);

      const soundToggle = screen.getByRole("switch", { name: /sound effects/i });
      await user.click(soundToggle);

      expect(onSave).toHaveBeenCalledWith(
        expect.objectContaining({
          sounds: false,
        })
      );
    });
  });

  describe("floating widget", () => {
    it("renders floating widget toggle", () => {
      render(<Settings settings={defaultSettings} onSave={vi.fn()} />);

      const widgetToggle = screen.getByRole("switch", {
        name: /floating widget/i,
      });
      expect(widgetToggle).not.toBeChecked();
    });

    it("calls onSave when floating widget toggled", async () => {
      const user = userEvent.setup();
      const onSave = vi.fn();
      render(<Settings settings={defaultSettings} onSave={onSave} />);

      const widgetToggle = screen.getByRole("switch", {
        name: /floating widget/i,
      });
      await user.click(widgetToggle);

      expect(onSave).toHaveBeenCalledWith(
        expect.objectContaining({
          floatingWidget: true,
        })
      );
    });
  });

  describe("hotkey settings", () => {
    it("validates hotkey format", async () => {
      const user = userEvent.setup();
      render(<Settings settings={defaultSettings} onSave={vi.fn()} />);

      const toggleInput = screen.getByLabelText(/toggle hotkey/i);
      await user.clear(toggleInput);
      await user.type(toggleInput, "invalid");

      expect(screen.getByText(/Invalid hotkey format/i)).toBeInTheDocument();
    });

    it("accepts valid hotkey format", async () => {
      const user = userEvent.setup();
      const onSave = vi.fn();
      render(<Settings settings={defaultSettings} onSave={onSave} />);

      const toggleInput = screen.getByLabelText(/toggle hotkey/i);
      await user.clear(toggleInput);
      await user.type(toggleInput, "Meta+Shift+K");
      await user.tab(); // Blur to trigger save

      expect(onSave).toHaveBeenCalledWith(
        expect.objectContaining({
          hotkeys: expect.objectContaining({
            toggle: "Meta+Shift+K",
          }),
        })
      );
    });
  });

  describe("reconciliation interval", () => {
    it("displays current interval", () => {
      render(<Settings settings={defaultSettings} onSave={vi.fn()} />);

      expect(screen.getByDisplayValue("6")).toBeInTheDocument();
    });

    it("updates interval on change", async () => {
      const user = userEvent.setup();
      const onSave = vi.fn();
      render(<Settings settings={defaultSettings} onSave={onSave} />);

      const intervalInput = screen.getByLabelText(/reconciliation/i);
      await user.clear(intervalInput);
      await user.type(intervalInput, "12");
      await user.tab();

      expect(onSave).toHaveBeenCalledWith(
        expect.objectContaining({
          reconciliationHours: 12,
        })
      );
    });
  });

  describe("default defer duration", () => {
    it("displays current default defer", () => {
      render(<Settings settings={defaultSettings} onSave={vi.fn()} />);

      const deferSelect = screen.getByLabelText(/default defer/i);
      expect(deferSelect).toHaveValue("1h");
    });

    it("updates default defer on change", async () => {
      const user = userEvent.setup();
      const onSave = vi.fn();
      render(<Settings settings={defaultSettings} onSave={onSave} />);

      const deferSelect = screen.getByLabelText(/default defer/i);
      await user.selectOptions(deferSelect, "3h");

      expect(onSave).toHaveBeenCalledWith(
        expect.objectContaining({
          defaultDefer: "3h",
        })
      );
    });
  });

  describe("keyboard shortcuts display", () => {
    it("shows keyboard shortcuts section", () => {
      render(<Settings settings={defaultSettings} onSave={vi.fn()} />);

      expect(screen.getByText(/keyboard shortcuts/i)).toBeInTheDocument();
    });

    it("displays common shortcuts", () => {
      render(<Settings settings={defaultSettings} onSave={vi.fn()} />);

      // Check for common shortcut displays
      expect(screen.getByText(/start task/i)).toBeInTheDocument();
      expect(screen.getByText(/skip task/i)).toBeInTheDocument();
      expect(screen.getByText(/command palette/i)).toBeInTheDocument();
    });
  });

  describe("lore path", () => {
    it("shows default lore path when null", () => {
      render(<Settings settings={defaultSettings} onSave={vi.fn()} />);

      expect(
        screen.getByPlaceholderText(/\.local\/share\/lore/i)
      ).toBeInTheDocument();
    });

    it("shows custom lore path when set", () => {
      const settingsWithPath = {
        ...defaultSettings,
        lorePath: "/custom/path/lore.db",
      };
      render(<Settings settings={settingsWithPath} onSave={vi.fn()} />);

      expect(screen.getByDisplayValue("/custom/path/lore.db")).toBeInTheDocument();
    });
  });

  describe("section organization", () => {
    it("groups settings into sections", () => {
      render(<Settings settings={defaultSettings} onSave={vi.fn()} />);

      // Check for section headers (h2 elements)
      expect(screen.getByRole("heading", { name: /appearance/i })).toBeInTheDocument();
      expect(screen.getByRole("heading", { name: /behavior/i })).toBeInTheDocument();
      expect(screen.getByRole("heading", { name: /hotkeys/i })).toBeInTheDocument();
      expect(screen.getByRole("heading", { name: /^data$/i })).toBeInTheDocument();
    });
  });
});
