import type { ClientPrefix } from "@/lib/types";
import {
	firstProblem,
	initPrefixEditor,
	isDirty,
	prefixEditorReducer,
	toInputs,
	type PrefixEditorState,
} from "./prefixEditor";

const server: ClientPrefix[] = [
	{ id: 1, prefix: "192.168.1.0/24", group_id: 1, group: "default", priority: 100 },
	{ id: 2, prefix: "10.0.0.0/8", group_id: 2, group: "kids", priority: 50 },
];

test("init mirrors the server rows into baseline and rows", () => {
	const state = initPrefixEditor(server);
	expect(state.rows).toEqual([
		{ prefix: "192.168.1.0/24", group_id: 1, priority: "100" },
		{ prefix: "10.0.0.0/8", group_id: 2, priority: "50" },
	]);
	expect(state.baseline).toEqual(state.rows);
	expect(isDirty(state)).toBe(false);
});

test("add appends an empty row with the given group and marks dirty", () => {
	const state = prefixEditorReducer(initPrefixEditor(server), { type: "add", groupId: 1 });
	expect(state.rows).toHaveLength(3);
	expect(state.rows[2]).toEqual({ prefix: "", group_id: 1, priority: "" });
	expect(isDirty(state)).toBe(true);
});

test("remove drops the row at the index", () => {
	const state = prefixEditorReducer(initPrefixEditor(server), { type: "remove", index: 0 });
	expect(state.rows).toEqual([{ prefix: "10.0.0.0/8", group_id: 2, priority: "50" }]);
	expect(isDirty(state)).toBe(true);
});

test("edit patches a single row", () => {
	const state = prefixEditorReducer(initPrefixEditor(server), {
		type: "edit",
		index: 1,
		patch: { group_id: 1, priority: "10" },
	});
	expect(state.rows[1]).toEqual({ prefix: "10.0.0.0/8", group_id: 1, priority: "10" });
	expect(state.rows[0]).toEqual(state.baseline[0]);
	expect(isDirty(state)).toBe(true);
});

test("editing a field back to its baseline value is clean again", () => {
	let state: PrefixEditorState = initPrefixEditor(server);
	state = prefixEditorReducer(state, { type: "edit", index: 0, patch: { priority: "7" } });
	expect(isDirty(state)).toBe(true);
	state = prefixEditorReducer(state, { type: "edit", index: 0, patch: { priority: "100" } });
	expect(isDirty(state)).toBe(false);
});

test("reset adopts new server rows and clears dirtiness", () => {
	let state = prefixEditorReducer(initPrefixEditor(server), { type: "add", groupId: 1 });
	state = prefixEditorReducer(state, { type: "reset", prefixes: server });
	expect(isDirty(state)).toBe(false);
	expect(state.rows).toHaveLength(2);
});

test("toInputs trims prefixes, parses priorities and omits empty ones", () => {
	expect(
		toInputs([
			{ prefix: " 192.168.1.0/24 ", group_id: 1, priority: "25" },
			{ prefix: "10.0.0.0/8", group_id: 2, priority: "" },
		]),
	).toEqual([
		{ prefix: "192.168.1.0/24", group_id: 1, priority: 25 },
		{ prefix: "10.0.0.0/8", group_id: 2 },
	]);
});

test("firstProblem flags empty prefixes and non-integer priorities", () => {
	expect(firstProblem([{ prefix: "10.0.0.0/8", group_id: 1, priority: "" }])).toBeNull();
	expect(firstProblem([{ prefix: "  ", group_id: 1, priority: "" }])).toEqual({
		index: 0,
		field: "prefix",
		message: "Row 1: prefix is required.",
	});
	expect(
		firstProblem([
			{ prefix: "10.0.0.0/8", group_id: 1, priority: "100" },
			{ prefix: "10.1.0.0/16", group_id: 1, priority: "abc" },
		]),
	).toEqual({ index: 1, field: "priority", message: "Row 2: priority must be a whole number." });
});
