package nextcloud

import (
	"strings"
	"testing"
)

func TestParseICSBasics(t *testing.T) {
	ics := strings.Join([]string{
		"BEGIN:VCALENDAR",
		"VERSION:2.0",
		"BEGIN:VTIMEZONE",
		"TZID:Europe/Paris",
		"BEGIN:STANDARD",
		"DTSTART:19961027T030000",
		"END:STANDARD",
		"END:VTIMEZONE",
		"BEGIN:VEVENT",
		"UID:abc-123",
		"SUMMARY:Réunion\\, équipe",
		"DESCRIPTION:Ligne 1\\nLigne 2",
		"DTSTART;TZID=Europe/Paris:20260611T100000",
		"DTEND;TZID=Europe/Paris:20260611T110000",
		"RRULE:FREQ=WEEKLY;BYDAY=TH",
		"EXDATE;TZID=Europe/Paris:20260618T100000",
		"END:VEVENT",
		"END:VCALENDAR",
	}, "\r\n")

	e := parseICS(ics)
	if e.UID != "abc-123" {
		t.Fatalf("UID = %q", e.UID)
	}
	if e.Summary != "Réunion, équipe" {
		t.Fatalf("Summary = %q", e.Summary)
	}
	if e.Description != "Ligne 1\nLigne 2" {
		t.Fatalf("Description = %q", e.Description)
	}
	// VTIMEZONE DTSTART must not leak into the event.
	if e.Start != "20260611T080000Z" {
		t.Fatalf("Start = %q, want UTC-converted 20260611T080000Z", e.Start)
	}
	if e.End != "20260611T090000Z" {
		t.Fatalf("End = %q", e.End)
	}
	if e.AllDay {
		t.Fatal("AllDay should be false")
	}
	if e.RRule != "FREQ=WEEKLY;BYDAY=TH" {
		t.Fatalf("RRule = %q", e.RRule)
	}
	if len(e.ExDates) != 1 || e.ExDates[0] != "20260618T080000Z" {
		t.Fatalf("ExDates = %v", e.ExDates)
	}
}

func TestParseICSAllDayAndFolding(t *testing.T) {
	ics := strings.Join([]string{
		"BEGIN:VCALENDAR",
		"BEGIN:VEVENT",
		"UID:x",
		"SUMMARY:Long title that",
		" continues folded",
		"DTSTART;VALUE=DATE:20260611",
		"DTEND;VALUE=DATE:20260612",
		"END:VEVENT",
		"END:VCALENDAR",
	}, "\r\n")

	e := parseICS(ics)
	if !e.AllDay {
		t.Fatal("AllDay should be true")
	}
	if e.Start != "20260611" || e.End != "20260612" {
		t.Fatalf("Start/End = %q/%q", e.Start, e.End)
	}
	if e.Summary != "Long title thatcontinues folded" {
		t.Fatalf("Summary = %q", e.Summary)
	}
}

func TestParseICSPrefersMasterVEvent(t *testing.T) {
	ics := strings.Join([]string{
		"BEGIN:VCALENDAR",
		"BEGIN:VEVENT",
		"UID:rec",
		"RECURRENCE-ID:20260618T100000Z",
		"SUMMARY:Exception",
		"DTSTART:20260618T120000Z",
		"DTEND:20260618T130000Z",
		"END:VEVENT",
		"BEGIN:VEVENT",
		"UID:rec",
		"SUMMARY:Master",
		"DTSTART:20260611T100000Z",
		"DTEND:20260611T110000Z",
		"RRULE:FREQ=DAILY",
		"END:VEVENT",
		"END:VCALENDAR",
	}, "\r\n")

	e := parseICS(ics)
	if e.Summary != "Master" {
		t.Fatalf("Summary = %q, want master VEVENT", e.Summary)
	}
}

func TestBuildICSRoundTrip(t *testing.T) {
	event := &Event{
		UID:         "round-trip",
		Summary:     "Point; hebdo, équipe",
		Description: "Ordre du jour:\npoint 1",
		Location:    "Salle A",
		Start:       "20260611T100000Z",
		End:         "20260611T110000Z",
		RRule:       "FREQ=WEEKLY;BYDAY=TH",
		ExDates:     []string{"20260618T100000Z"},
		Color:       "#1A73E8",
		Attendees: []EventAttendee{
			{Email: "invite@example.com", Name: "Invité", Status: "ACCEPTED"},
		},
	}
	parsed := parseICS(buildICS(event))
	if parsed.Summary != event.Summary {
		t.Fatalf("Summary = %q", parsed.Summary)
	}
	if parsed.Description != event.Description {
		t.Fatalf("Description = %q", parsed.Description)
	}
	if parsed.RRule != event.RRule {
		t.Fatalf("RRule = %q", parsed.RRule)
	}
	if parsed.Color != "" {
		t.Fatalf("Color should not be serialized in ICS, got %q", parsed.Color)
	}
	if len(parsed.ExDates) != 1 || parsed.ExDates[0] != "20260618T100000Z" {
		t.Fatalf("ExDates = %v", parsed.ExDates)
	}
	if len(parsed.Attendees) != 1 || parsed.Attendees[0].Email != "invite@example.com" || parsed.Attendees[0].Status != "ACCEPTED" {
		t.Fatalf("Attendees = %+v", parsed.Attendees)
	}
	if parsed.Start != event.Start || parsed.End != event.End {
		t.Fatalf("Start/End = %q/%q", parsed.Start, parsed.End)
	}
}

func TestMergeEventPreservesUID(t *testing.T) {
	existing := &Event{
		UID:         "abc@ulti",
		Summary:     "Original",
		Start:       "20260611T100000Z",
		End:         "20260611T110000Z",
		Path:        "/remote.php/dav/calendars/user/personal/abc@ulti.ics",
		MeetURL:     "https://meet.example/room",
		ExDates:     []string{"20260618T100000Z"},
	}
	patch := &Event{
		Summary: "Updated title",
		Start:   "20260612T100000Z",
		End:     "20260612T110000Z",
	}
	merged := MergeEvent(existing, patch)
	if merged.UID != "abc@ulti" {
		t.Fatalf("UID = %q", merged.UID)
	}
	if merged.Summary != "Updated title" {
		t.Fatalf("Summary = %q", merged.Summary)
	}
	if merged.MeetURL != "https://meet.example/room" {
		t.Fatalf("MeetURL should be preserved, got %q", merged.MeetURL)
	}
	if len(merged.ExDates) != 1 {
		t.Fatalf("ExDates = %v", merged.ExDates)
	}
}

func TestMergeEventUIDFromPath(t *testing.T) {
	existing := &Event{
		Summary: "Keep",
		Path:    "/remote.php/dav/calendars/user/personal/fallback@ulti.ics",
	}
	patch := &Event{Summary: "New"}
	merged := MergeEvent(existing, patch)
	if merged.UID != "fallback@ulti" {
		t.Fatalf("UID = %q", merged.UID)
	}
}

func TestBuildICSAllDay(t *testing.T) {
	ics := buildICS(&Event{UID: "ad", Summary: "Férié", Start: "20260714", End: "20260715", AllDay: true})
	if !strings.Contains(ics, "DTSTART;VALUE=DATE:20260714") {
		t.Fatalf("missing all-day DTSTART:\n%s", ics)
	}
	parsed := parseICS(ics)
	if !parsed.AllDay {
		t.Fatal("AllDay should round-trip")
	}
}

func TestParseCalendarListNormalizesCloudPrefix(t *testing.T) {
	basePath := "/remote.php/dav/calendars/user@example.com/"
	raw := `<?xml version="1.0" encoding="UTF-8"?>
<d:multistatus xmlns:d="DAV:" xmlns:apple="http://apple.com/ns/ical/">
  <d:response>
    <d:href>/cloud/remote.php/dav/calendars/user@example.com/</d:href>
    <d:propstat><d:prop><d:displayname>Root</d:displayname></d:prop></d:propstat>
  </d:response>
  <d:response>
    <d:href>/cloud/remote.php/dav/calendars/user@example.com/personal/</d:href>
    <d:propstat><d:prop>
      <d:displayname>Personal</d:displayname>
      <apple:calendar-color>#1a73e8</apple:calendar-color>
    </d:prop></d:propstat>
  </d:response>
</d:multistatus>`

	cals, err := parseCalendarList(strings.NewReader(raw), basePath)
	if err != nil {
		t.Fatal(err)
	}
	if len(cals) != 1 {
		t.Fatalf("len = %d, want 1", len(cals))
	}
	if cals[0].ID != "personal" {
		t.Fatalf("ID = %q, want personal", cals[0].ID)
	}
	if cals[0].Path != "/remote.php/dav/calendars/user@example.com/personal/" {
		t.Fatalf("Path = %q", cals[0].Path)
	}
}
