import { afterEach, beforeEach, describe, expect, it } from "bun:test";
import { mkdir, rm } from "node:fs/promises";
import { $ } from "bun";
import { Core } from "../core/backlog.ts";
import { type ViewState, ViewSwitcher } from "../ui/view-switcher.ts";
import { createUniqueTestDir, initializeTestProject, safeCleanup } from "./test-utils.ts";

describe("View Switcher", () => {
	let TEST_DIR: string;
	let core: Core;

	beforeEach(async () => {
		TEST_DIR = createUniqueTestDir("test-view-switcher");
		await rm(TEST_DIR, { recursive: true, force: true }).catch(() => {});
		await mkdir(TEST_DIR, { recursive: true });

		// Configure git for tests - required for CI
		await $`git init`.cwd(TEST_DIR).quiet();
		await $`git config user.email test@example.com`.cwd(TEST_DIR).quiet();
		await $`git config user.name "Test User"`.cwd(TEST_DIR).quiet();

		core = new Core(TEST_DIR);
		await initializeTestProject(core, "Test View Switcher Project");

		// Disable remote operations for tests to prevent background git fetches
		const config = await core.filesystem.loadConfig();
		if (config) {
			config.remoteOperations = false;
			await core.filesystem.saveConfig(config);
		}
	});

	afterEach(async () => {
		try {
			await safeCleanup(TEST_DIR);
		} catch {
			// Ignore cleanup errors - the unique directory names prevent conflicts
		}
	});

	describe("ViewSwitcher initialization", () => {
		it("should initialize with task-list view", () => {
			const initialState: ViewState = {
				type: "task-list",
				tasks: [],
			};

			const switcher = new ViewSwitcher({
				core,
				initialState,
			});

			const state = switcher.getState();
			expect(state.type).toBe("task-list");
			expect(state.tasks).toEqual([]);
		});

		it("should initialize with task-detail view", () => {
			const selectedTask = {
				id: "task-1",
				title: "Test Task",
				status: "To Do",
				assignee: [],
				createdDate: "2025-07-05",
				labels: [],
				dependencies: [],
				rawContent: "Test task body",
			};

			const initialState: ViewState = {
				type: "task-detail",
				selectedTask,
				tasks: [selectedTask],
			};

			const switcher = new ViewSwitcher({
				core,
				initialState,
			});

			const state = switcher.getState();
			expect(state.type).toBe("task-detail");
			expect(state.selectedTask).toEqual(selectedTask);
		});

		it("should initialize with kanban view", () => {
			const initialState: ViewState = {
				type: "kanban",
				kanbanData: {
					tasks: [],
					statuses: [],
					isLoading: true,
				},
			};

			const switcher = new ViewSwitcher({
				core,
				initialState,
			});

			const state = switcher.getState();
			expect(state.type).toBe("kanban");
			expect(state.kanbanData?.isLoading).toBe(true);
		});
	});

	describe("State updates", () => {
		it("should update state correctly", () => {
			const initialState: ViewState = {
				type: "task-list",
				tasks: [],
			};

			const switcher = new ViewSwitcher({
				core,
				initialState,
			});

			const newTask = {
				id: "task-1",
				title: "Updated Task",
				status: "In Progress",
				assignee: [],
				createdDate: "2025-07-05",
				labels: [],
				dependencies: [],
				rawContent: "Updated task body",
			};

			const updatedState = switcher.updateState({
				selectedTask: newTask,
				type: "task-detail",
			});

			expect(updatedState.type).toBe("task-detail");
			expect(updatedState.selectedTask).toEqual(newTask);
		});
	});

	describe("Background loading", () => {
		it("should indicate when kanban data is ready", () => {
			const initialState: ViewState = {
				type: "task-list",
				tasks: [],
			};

			const switcher = new ViewSwitcher({
				core,
				initialState,
			});

			// Initially should not be ready (no data loaded yet)
			expect(switcher.isKanbanReady()).toBe(false);
		});

		it("should start preloading kanban data", () => {
			const initialState: ViewState = {
				type: "task-list",
				tasks: [],
			};

			const switcher = new ViewSwitcher({
				core,
				initialState,
			});

			// Mock the preloadKanban method to avoid remote git operations
			switcher.preloadKanban = async () => {};

			// Should not throw when preloading
			expect(() => switcher.preloadKanban()).not.toThrow();
		});
	});

	describe("View change callback", () => {
		it("should call onViewChange when state updates", () => {
			let callbackState: ViewState | null = null;

			const initialState: ViewState = {
				type: "task-list",
				tasks: [],
			};

			const switcher = new ViewSwitcher({
				core,
				initialState,
				onViewChange: (newState) => {
					callbackState = newState;
				},
			});

			const newTask = {
				id: "task-1",
				title: "Test Task",
				status: "To Do",
				assignee: [],
				createdDate: "2025-07-05",
				labels: [],
				dependencies: [],
				rawContent: "Test task body",
			};

			switcher.updateState({
				selectedTask: newTask,
				type: "task-detail",
			});

			expect(callbackState).toBeTruthy();
			if (!callbackState) {
				throw new Error("callbackState should not be null");
			}
			const state = callbackState as unknown as ViewState;
			expect(state.type).toBe("task-detail");
			expect(state.selectedTask).toEqual(newTask);
		});
	});
});
