// biome-ignore-all lint/style/noNonNullAssertion: These tests assert imported section lengths before inspecting the first item.
import { describe, expect, it } from "vitest";
import { parseJSONResume } from "./json-resume";

describe("parseJSONResume", () => {
	it("throws when input is not valid JSON", () => {
		expect(() => parseJSONResume("not json")).toThrow();
	});

	it("throws a serialized validation error for an obviously invalid shape", () => {
		// Email field is validated; a non-email string should fail the loose schema.
		const invalid = JSON.stringify({ basics: { email: "not-an-email" } });
		expect(() => parseJSONResume(invalid)).toThrow();
	});

	it("imports an empty JSON Resume into a baseline ResumeData", () => {
		const result = parseJSONResume("{}");
		// Defaults preserve a name field even when unset by input.
		expect(typeof result.basics.name).toBe("string");
	});

	it("imports basics fields into ResumeData", () => {
		const json = JSON.stringify({
			basics: {
				name: "Jane Doe",
				label: "Engineer",
				email: "jane@example.com",
				phone: "+1 555 123 4567",
				url: "https://janedoe.dev",
				summary: "Software engineer with 10+ years building products.",
				location: { city: "Berlin", region: "BE", countryCode: "DE" },
			},
		});

		const result = parseJSONResume(json);
		expect(result.basics.name).toBe("Jane Doe");
		expect(result.basics.headline).toBe("Engineer");
		expect(result.basics.email).toBe("jane@example.com");
		expect(result.basics.phone).toBe("+1 555 123 4567");
		expect(result.basics.location).toBe("Berlin, BE, DE");
		expect(result.summary.content).toContain("Software engineer");
		expect(result.summary.hidden).toBe(false);
	});

	it("maps work entries into the experience section", () => {
		const json = JSON.stringify({
			work: [
				{
					name: "Acme Corp",
					position: "Senior Engineer",
					location: "Berlin",
					startDate: "2020-01-15",
					endDate: "2024",
					url: "https://acme.example",
					summary: "Built cool stuff.",
					highlights: ["Shipped X", "Improved Y by 30%"],
				},
				// Entry with neither name nor position is filtered out.
				{ startDate: "2010", endDate: "2015" },
			],
		});

		const result = parseJSONResume(json);
		expect(result.sections.experience.items).toHaveLength(1);

		const item = result.sections.experience.items[0]!;
		expect(item.company).toBe("Acme Corp");
		expect(item.position).toBe("Senior Engineer");
		expect(item.location).toBe("Berlin");
		expect(item.period.length).toBeGreaterThan(0);
		expect(item.description).toContain("Shipped X");
	});

	it("maps education entries (filters when institution is missing)", () => {
		const json = JSON.stringify({
			education: [
				{
					institution: "MIT",
					studyType: "BS",
					area: "Computer Science",
					startDate: "2010",
					endDate: "2014",
					score: "3.9",
					courses: ["Algorithms", "Distributed Systems"],
				},
				{ studyType: "BS" }, // no institution → filtered
			],
		});

		const result = parseJSONResume(json);
		expect(result.sections.education.items).toHaveLength(1);

		const edu = result.sections.education.items[0]!;
		expect(edu.school).toBe("MIT");
		expect(edu.degree).toBe("BS in Computer Science");
		expect(edu.description).toContain("Algorithms");
	});

	it("maps skills with level parsing", () => {
		const json = JSON.stringify({
			skills: [{ name: "TypeScript", level: "Master", keywords: ["node", "react"] }],
		});

		const result = parseJSONResume(json);
		const skill = result.sections.skills.items[0]!;

		expect(skill.name).toBe("TypeScript");
		expect(skill.keywords).toEqual(["node", "react"]);
		expect(skill.level).toBeGreaterThan(0);
	});

	it("maps profiles from basics.profiles into the profiles section", () => {
		const json = JSON.stringify({
			basics: {
				profiles: [
					{ network: "GitHub", username: "janedoe", url: "https://github.com/janedoe" },
					{ username: "no-network" }, // missing network → filtered
				],
			},
		});

		const result = parseJSONResume(json);
		expect(result.sections.profiles.items).toHaveLength(1);

		const profile = result.sections.profiles.items[0]!;
		expect(profile.network).toBe("GitHub");
		expect(profile.username).toBe("janedoe");
	});

	it("imports a picture URL from basics.image", () => {
		const json = JSON.stringify({
			basics: { image: "https://example.com/pic.jpg" },
		});

		const result = parseJSONResume(json);
		expect(result.picture.url).toBe("https://example.com/pic.jpg");
		expect(result.picture.hidden).toBe(false);
	});

	it("leaves the summary content empty when basics.summary is absent", () => {
		const result = parseJSONResume(JSON.stringify({ basics: { name: "Jane" } }));
		expect(result.summary.content).toBe("");
	});

	it("imports projects with description and period", () => {
		const json = JSON.stringify({
			projects: [
				{
					name: "Open source CLI",
					description: "Built a CLI tool",
					highlights: ["10k stars", "Used in production"],
					startDate: "2022",
					endDate: "2023",
					url: "https://github.com/x/y",
				},
				{ description: "no name" }, // filtered
			],
		});

		const result = parseJSONResume(json);
		expect(result.sections.projects.items).toHaveLength(1);

		const project = result.sections.projects.items[0]!;
		expect(project.name).toBe("Open source CLI");
		expect(project.description).toContain("10k stars");
	});
});
