import { describe, expect, it } from "vitest";
import { blankField, finalise, problemAt, setAnswer, TEMP, type FormEntry } from "./formLayout";

const core = (id: string, answer: FormEntry["answer"] = "optional"): FormEntry => ({
    id,
    label: "",
    placeholder: "",
    help: "",
    width: "full",
    answer,
    custom: false,
    type: "text",
    options: [],
    email: false,
});

const named = (id: string, label: string, type: FormEntry["type"] = "text"): FormEntry => ({ ...blankField(id, type), label });

describe("finalise", () => {
    it("names a new field after its label, accents dropped", () => {
        const out = finalise([core("date"), named(`${TEMP}1`, "  Dịp đặc biệt ")]);

        expect(out.problem).toBeNull();
        expect(out.fields[1]?.id).toBe("dip_dac_biet");
        expect(out.fields[1]?.label).toBe("Dịp đặc biệt");
        expect(out.renames.get(`${TEMP}1`)).toBe("dip_dac_biet");
    });

    it("keeps ids unique, core ids included, and starts them with a letter", () => {
        const out = finalise([core("email"), named("seating", "Seating"), named(`${TEMP}1`, "Email"), named(`${TEMP}2`, "Seating"), named(`${TEMP}3`, "2 cakes")]);

        expect(out.fields.map((f) => f.id)).toEqual(["email", "seating", "email_2", "seating_2", "field_2_cakes"]);
    });

    it("keeps a saved field's id when its label changes", () => {
        expect(finalise([named("seating", "Where to sit")]).fields[0]?.id).toBe("seating");
    });

    it("points at a custom field without a label", () => {
        const out = finalise([core("notes"), named(`${TEMP}4`, " ")]);

        expect(out.problem).toEqual({ id: `${TEMP}4`, field: "label", message: "Give the field a label." });
    });

    it("gives choices a value from their label and drops empty ones", () => {
        const field = { ...named("occasion", "Occasion", "select"), options: [{ value: "", label: "Birthday" }, { value: "", label: " " }, { value: "", label: "Birthday" }, { value: "x", label: "Kept" }] };
        const out = finalise([field]);

        expect(out.fields[0]?.options).toEqual([
            { value: "birthday", label: "Birthday" },
            { value: "birthday_2", label: "Birthday" },
            { value: "x", label: "Kept" },
        ]);
    });

    it("asks for a choice when all are empty", () => {
        expect(finalise([named("occasion", "Occasion", "radio")]).problem?.field).toBe("options");
    });

    it("drops the placeholder of a field that shows none", () => {
        expect(finalise([{ ...named("ok", "OK", "checkbox"), placeholder: "tick" }]).fields[0]?.placeholder).toBe("");
    });
});

describe("setAnswer", () => {
    it("makes the other contact required when one is hidden", () => {
        const out = setAnswer([core("phone"), core("email")], "phone", "hidden");

        expect(out.map((f) => f.answer)).toEqual(["hidden", "required"]);
        expect(setAnswer(out, "phone", "optional").map((f) => f.answer)).toEqual(["optional", "required"]);
    });
});

describe("problemAt", () => {
    it("reads the server's path", () => {
        const fields = [core("date"), named("occasion", "Occasion")];

        expect(problemAt(fields, "fields.1.options", "No")).toEqual({ id: "occasion", field: "options", message: "No" });
        expect(problemAt(fields, "fields.0", "No")?.field).toBe("id");
        expect(problemAt(fields, "fields", "No")).toBeNull();
        expect(problemAt(fields, "fields.9.label", "No")).toBeNull();
    });
});
