import Testing
import Foundation
@testable import TaskStore

@Suite("VTODOFormatter")
struct VTODOFormatterTests {

	private let fixedDate = Date(timeIntervalSince1970: 1_773_763_200) // 2026-03-15T12:00:00Z

	@Test("formats minimal VTODO with required fields only")
	func minimalFormat() {
		let result = VTODOFormatter.format(
			uid: "task-001",
			summary: "Test task",
			createdAt: fixedDate,
			updatedAt: fixedDate
		)

		#expect(result.contains("BEGIN:VCALENDAR"))
		#expect(result.contains("VERSION:2.0"))
		#expect(result.contains("PRODID:-//MagnumOpus//TaskStore//EN"))
		#expect(result.contains("BEGIN:VTODO"))
		#expect(result.contains("UID:task-001"))
		#expect(result.contains("SUMMARY:Test task"))
		#expect(result.contains("STATUS:NEEDS-ACTION"))
		#expect(result.contains("PRIORITY:0"))
		#expect(result.contains("END:VTODO"))
		#expect(result.contains("END:VCALENDAR"))
		// Should NOT contain optional fields
		#expect(!result.contains("DESCRIPTION:"))
		#expect(!result.contains("DUE;"))
		#expect(!result.contains("DTSTART;"))
		#expect(!result.contains("CATEGORIES:"))
		#expect(!result.contains("ATTACH:"))
		#expect(!result.contains("X-MAGNUM-SOMEDAY"))
	}

	@Test("formats all optional fields")
	func optionalFields() {
		let dueDate = VTODOParser.parseDate("20260320")!
		let deferDate = VTODOParser.parseDate("20260318")!

		let result = VTODOFormatter.format(
			uid: "task-002",
			summary: "Full task",
			description: "A detailed description",
			status: "IN-PROCESS",
			priority: 5,
			dueDate: dueDate,
			deferUntil: deferDate,
			categories: ["work", "urgent"],
			linkedMessageId: "msg-123@example.com",
			isSomeday: false,
			createdAt: fixedDate,
			updatedAt: fixedDate
		)

		#expect(result.contains("DESCRIPTION:A detailed description"))
		#expect(result.contains("DUE;VALUE=DATE:20260320"))
		#expect(result.contains("DTSTART;VALUE=DATE:20260318"))
		#expect(result.contains("CATEGORIES:work,urgent"))
		#expect(result.contains("ATTACH:mid:msg-123@example.com"))
		#expect(!result.contains("X-MAGNUM-SOMEDAY"))
	}

	@Test("includes someday flag when true")
	func somedayFlag() {
		let result = VTODOFormatter.format(
			uid: "task-003",
			summary: "Someday task",
			isSomeday: true,
			createdAt: fixedDate,
			updatedAt: fixedDate
		)

		#expect(result.contains("X-MAGNUM-SOMEDAY:TRUE"))
	}

	@Test("escapes special characters in text")
	func specialCharacterEscaping() {
		let result = VTODOFormatter.format(
			uid: "task-004",
			summary: "Buy milk, eggs; bread",
			description: "Line1\nLine2\\end",
			createdAt: fixedDate,
			updatedAt: fixedDate
		)

		#expect(result.contains("SUMMARY:Buy milk\\, eggs\\; bread"))
		#expect(result.contains("DESCRIPTION:Line1\\nLine2\\\\end"))
	}

	@Test("escapeText works correctly")
	func escapeText() {
		#expect(VTODOFormatter.escapeText("a,b") == "a\\,b")
		#expect(VTODOFormatter.escapeText("a;b") == "a\\;b")
		#expect(VTODOFormatter.escapeText("a\nb") == "a\\nb")
		#expect(VTODOFormatter.escapeText("a\\b") == "a\\\\b")
		#expect(VTODOFormatter.escapeText("plain") == "plain")
	}

	@Test("foldLine folds long lines at 75 octets")
	func foldLineLong() {
		let longLine = String(repeating: "A", count: 100)
		let folded = VTODOFormatter.foldLine(longLine)
		let parts = folded.components(separatedBy: "\r\n")
		#expect(parts.count == 2)
		#expect(parts[0].utf8.count == 75)
		#expect(parts[1].hasPrefix(" "))
	}

	@Test("foldLine does not fold short lines")
	func foldLineShort() {
		let shortLine = "SUMMARY:Short"
		#expect(VTODOFormatter.foldLine(shortLine) == shortLine)
	}

	// MARK: - Round-trip

	@Test("format then parse round-trip preserves properties")
	func roundTrip() {
		let dueDate = VTODOParser.parseDate("20260320")!

		let formatted = VTODOFormatter.format(
			uid: "rt-001",
			summary: "Round trip test, with commas; and semicolons",
			description: "Line 1\nLine 2",
			status: "IN-PROCESS",
			priority: 3,
			dueDate: dueDate,
			categories: ["cat1", "cat2"],
			linkedMessageId: "msg@example.com",
			isSomeday: true,
			createdAt: fixedDate,
			updatedAt: fixedDate
		)

		let parsed = VTODOParser.parse(formatted)
		#expect(parsed != nil)
		#expect(parsed?["UID"] == "rt-001")
		#expect(parsed?["SUMMARY"] == "Round trip test, with commas; and semicolons")
		#expect(parsed?["DESCRIPTION"] == "Line 1\nLine 2")
		#expect(parsed?["STATUS"] == "IN-PROCESS")
		#expect(parsed?["PRIORITY"] == "3")
		#expect(parsed?["DUE"] == "20260320")
		#expect(parsed?["CATEGORIES"] == "cat1,cat2")
		#expect(parsed?["ATTACH"] == "mid:msg@example.com")
		#expect(parsed?["X-MAGNUM-SOMEDAY"] == "TRUE")
	}
}
