import test from "node:test";
import assert from "node:assert/strict";
import request from "supertest";
import { setup, signup, password } from "./helpers.js";

async function bootstrapAdmin(agent) {
	const response = await agent.post("/api/auth/bootstrap").send({
		email: "snowspeeder@gmail.com",
		password,
		setupToken: "a-secure-bootstrap-token",
	});
	assert.equal(response.status, 201);
	return response.body.csrfToken;
}

test("plans: custom name is created, listed, and defaults to blank", async () => {
	const { agent } = await setup();
	const { csrf } = await signup(agent, "planner@example.com");

	const unnamed = await agent
		.post("/api/plans")
		.set("x-csrf-token", csrf)
		.send({ plan: { fields: { 0.1: "House blend" } } });
	assert.equal(unnamed.status, 201);
	assert.equal(unnamed.body.plan.name, "");

	const named = await agent
		.post("/api/plans")
		.set("x-csrf-token", csrf)
		.send({ plan: { fields: { 0.1: "House blend" } }, name: "  Winter batch  " });
	assert.equal(named.status, 201);
	assert.equal(named.body.plan.name, "Winter batch", "name is trimmed");

	const list = (await agent.get("/api/plans")).body.plans;
	assert.equal(list.find((p) => p.id === named.body.plan.id).name, "Winter batch");
	assert.equal(list.find((p) => p.id === unnamed.body.plan.id).name, "");
});

test("plans: PUT name-only preserves the plan JSONB, and PUT plan-only preserves the name", async () => {
	const { agent } = await setup();
	const { csrf } = await signup(agent, "planner2@example.com");

	const created = await agent
		.post("/api/plans")
		.set("x-csrf-token", csrf)
		.send({ plan: { fields: { 0.1: "Original title", "0.4": "300" } }, name: "First name" });
	const planId = created.body.plan.id;

	// Name-only update: the plan JSONB is untouched.
	const renamed = await agent
		.put(`/api/plans/${planId}`)
		.set("x-csrf-token", csrf)
		.send({ name: "Second name" });
	assert.equal(renamed.status, 200);
	assert.equal(renamed.body.plan.name, "Second name");
	assert.equal(renamed.body.plan.plan.fields["0.1"], "Original title");
	assert.equal(renamed.body.plan.plan.fields["0.4"], "300");

	// Plan-only update: the name is untouched.
	const replanned = await agent
		.put(`/api/plans/${planId}`)
		.set("x-csrf-token", csrf)
		.send({ plan: { fields: { 0.1: "New title", "0.4": "350" } } });
	assert.equal(replanned.status, 200);
	assert.equal(replanned.body.plan.name, "Second name");
	assert.equal(replanned.body.plan.plan.fields["0.1"], "New title");

	// Both at once.
	const both = await agent
		.put(`/api/plans/${planId}`)
		.set("x-csrf-token", csrf)
		.send({ plan: { fields: { 0.1: "Third title" } }, name: "Third name" });
	assert.equal(both.body.plan.name, "Third name");
	assert.equal(both.body.plan.plan.fields["0.1"], "Third title");

	// Neither field present: bad request, same as the pre-existing plan-required behavior.
	assert.equal(
		(await agent.put(`/api/plans/${planId}`).set("x-csrf-token", csrf).send({})).status,
		400,
	);
});

test("plans: ownership — a stranger cannot rename another user's plan", async () => {
	const { app } = await setup();
	const owner = request.agent(app);
	const stranger = request.agent(app);
	const { csrf: ownerCsrf } = await signup(owner, "owner@example.com");
	const { csrf: strangerCsrf } = await signup(stranger, "stranger@example.com");

	const created = await owner
		.post("/api/plans")
		.set("x-csrf-token", ownerCsrf)
		.send({ plan: { fields: { 0.1: "Owner's plan" } } });
	const planId = created.body.plan.id;

	const hijack = await stranger
		.put(`/api/plans/${planId}`)
		.set("x-csrf-token", strangerCsrf)
		.send({ name: "Hijacked" });
	assert.equal(hijack.status, 404);

	// The plan is unaffected.
	const stillOwners = (await owner.get("/api/plans")).body.plans;
	assert.equal(stillOwners.find((p) => p.id === planId).name, "");
});

test("plans: admin plan list title falls back to worksheet field 0.1 when no custom name is set", async () => {
	const { app } = await setup();
	const admin = request.agent(app);
	await bootstrapAdmin(admin);

	const user = request.agent(app);
	const { csrf: userCsrf } = await signup(user, "regular@example.com");

	const named = await user
		.post("/api/plans")
		.set("x-csrf-token", userCsrf)
		.send({ plan: { fields: { 0.1: "Worksheet title" } }, name: "Custom title" });
	const unnamed = await user
		.post("/api/plans")
		.set("x-csrf-token", userCsrf)
		.send({ plan: { fields: { 0.1: "Worksheet title only" } } });

	const list = (await admin.get("/api/admin/plans")).body.plans;
	assert.equal(list.find((p) => p.id === named.body.plan.id).title, "Custom title");
	assert.equal(
		list.find((p) => p.id === unnamed.body.plan.id).title,
		"Worksheet title only",
	);
});
