package tools

import (
	"path/filepath"
	"testing"

	"skraak/utils"
)

func TestCallsModifyBookmark(t *testing.T) {
	// Create a temp .data file with a bookmarked segment
	tmpDir := t.TempDir()
	tmpFile := filepath.Join(tmpDir, "test.data")

	df := &utils.DataFile{
		Meta: &utils.DataMeta{Operator: "test", Duration: 60},
		Segments: []*utils.Segment{
			{
				StartTime: 10.0,
				EndTime:   15.0,
				FreqLow:   100,
				FreqHigh:  5000,
				Labels: []*utils.Label{
					{Species: "Kiwi", Certainty: 80, Filter: "myfilter", CallType: "Duet", Bookmark: true},
				},
			},
		},
	}
	if err := df.Write(tmpFile); err != nil {
		t.Fatalf("failed to write test file: %v", err)
	}

	// Test 1: Adding bookmark when already true should do nothing
	bookmark := true
	result, err := CallsModify(CallsModifyInput{
		File:      tmpFile,
		Reviewer:  "tester",
		Filter:    "myfilter",
		Segment:   "10-15",
		Certainty: 80,
		Bookmark:  &bookmark,
	})

	// Should return error "no changes needed"
	if err == nil {
		t.Errorf("expected error 'no changes needed' when bookmark already true, got nil")
	}
	if result.Error != "No changes needed: all values already match" {
		t.Errorf("expected 'no changes needed' error, got: %s", result.Error)
	}

	// Verify bookmark is still true in the file
	df2, err := utils.ParseDataFile(tmpFile)
	if err != nil {
		t.Fatalf("failed to parse file: %v", err)
	}
	if !df2.Segments[0].Labels[0].Bookmark {
		t.Errorf("bookmark should still be true, got false")
	}
}

func TestCallsModifyBookmarkFalse(t *testing.T) {
	// Create a temp .data file WITHOUT a bookmark
	tmpDir := t.TempDir()
	tmpFile := filepath.Join(tmpDir, "test.data")

	df := &utils.DataFile{
		Meta: &utils.DataMeta{Operator: "test", Duration: 60},
		Segments: []*utils.Segment{
			{
				StartTime: 10.0,
				EndTime:   15.0,
				FreqLow:   100,
				FreqHigh:  5000,
				Labels: []*utils.Label{
					{Species: "Kiwi", Certainty: 80, Filter: "myfilter", CallType: "Duet", Bookmark: false},
				},
			},
		},
	}
	if err := df.Write(tmpFile); err != nil {
		t.Fatalf("failed to write test file: %v", err)
	}

	// Test: Adding bookmark when false should set it to true
	bookmark := true
	result, err := CallsModify(CallsModifyInput{
		File:      tmpFile,
		Reviewer:  "tester",
		Filter:    "myfilter",
		Segment:   "10-15",
		Certainty: 80,
		Bookmark:  &bookmark,
	})

	if err != nil {
		t.Errorf("unexpected error: %v", err)
	}
	if result.Bookmark == nil || !*result.Bookmark {
		t.Errorf("expected bookmark=true in result, got %v", result.Bookmark)
	}

	// Verify bookmark is true in the file
	df2, err := utils.ParseDataFile(tmpFile)
	if err != nil {
		t.Fatalf("failed to parse file: %v", err)
	}
	if !df2.Segments[0].Labels[0].Bookmark {
		t.Errorf("bookmark should be true, got false")
	}
}

func TestCallsModifyCommentAdditive(t *testing.T) {
	// Create a temp .data file with an existing comment
	tmpDir := t.TempDir()
	tmpFile := filepath.Join(tmpDir, "test.data")

	df := &utils.DataFile{
		Meta: &utils.DataMeta{Operator: "test", Duration: 60},
		Segments: []*utils.Segment{
			{
				StartTime: 10.0,
				EndTime:   15.0,
				FreqLow:   100,
				FreqHigh:  5000,
				Labels: []*utils.Label{
					{Species: "Kiwi", Certainty: 80, Filter: "myfilter", Comment: "First observation"},
				},
			},
		},
	}
	if err := df.Write(tmpFile); err != nil {
		t.Fatalf("failed to write test file: %v", err)
	}

	// Test: Adding comment should be additive
	result, err := CallsModify(CallsModifyInput{
		File:      tmpFile,
		Reviewer:  "tester",
		Filter:    "myfilter",
		Segment:   "10-15",
		Certainty: 80,
		Comment:   "Good example",
	})

	if err != nil {
		t.Errorf("unexpected error: %v", err)
	}

	expectedComment := "First observation | Good example"
	if result.Comment != expectedComment {
		t.Errorf("expected comment=%q, got %q", expectedComment, result.Comment)
	}

	// Verify comment in file
	df2, err := utils.ParseDataFile(tmpFile)
	if err != nil {
		t.Fatalf("failed to parse file: %v", err)
	}
	if df2.Segments[0].Labels[0].Comment != expectedComment {
		t.Errorf("expected comment in file=%q, got %q", expectedComment, df2.Segments[0].Labels[0].Comment)
	}
}

func TestCallsModifyCommentAdditiveMultiple(t *testing.T) {
	// Create a temp .data file and add multiple comments
	tmpDir := t.TempDir()
	tmpFile := filepath.Join(tmpDir, "test.data")

	df := &utils.DataFile{
		Meta: &utils.DataMeta{Operator: "test", Duration: 60},
		Segments: []*utils.Segment{
			{
				StartTime: 10.0,
				EndTime:   15.0,
				FreqLow:   100,
				FreqHigh:  5000,
				Labels: []*utils.Label{
					{Species: "Kiwi", Certainty: 80, Filter: "myfilter"},
				},
			},
		},
	}
	if err := df.Write(tmpFile); err != nil {
		t.Fatalf("failed to write test file: %v", err)
	}

	// Add first comment
	_, err := CallsModify(CallsModifyInput{
		File:      tmpFile,
		Reviewer:  "tester",
		Filter:    "myfilter",
		Segment:   "10-15",
		Certainty: 80,
		Comment:   "First",
	})
	if err != nil {
		t.Fatalf("unexpected error on first comment: %v", err)
	}

	// Add second comment
	_, err = CallsModify(CallsModifyInput{
		File:      tmpFile,
		Reviewer:  "tester",
		Filter:    "myfilter",
		Segment:   "10-15",
		Certainty: 80,
		Comment:   "Second",
	})
	if err != nil {
		t.Fatalf("unexpected error on second comment: %v", err)
	}

	// Add third comment
	result, err := CallsModify(CallsModifyInput{
		File:      tmpFile,
		Reviewer:  "tester",
		Filter:    "myfilter",
		Segment:   "10-15",
		Certainty: 80,
		Comment:   "Third",
	})
	if err != nil {
		t.Fatalf("unexpected error on third comment: %v", err)
	}

	expectedComment := "First | Second | Third"
	if result.Comment != expectedComment {
		t.Errorf("expected comment=%q, got %q", expectedComment, result.Comment)
	}
}

func TestCallsModifyCommentTooLong(t *testing.T) {
	// Create a temp .data file with an existing long comment
	tmpDir := t.TempDir()
	tmpFile := filepath.Join(tmpDir, "test.data")

	existingComment := "This is a fairly long existing comment that takes up space"
	df := &utils.DataFile{
		Meta: &utils.DataMeta{Operator: "test", Duration: 60},
		Segments: []*utils.Segment{
			{
				StartTime: 10.0,
				EndTime:   15.0,
				FreqLow:   100,
				FreqHigh:  5000,
				Labels: []*utils.Label{
					{Species: "Kiwi", Certainty: 80, Filter: "myfilter", Comment: existingComment},
				},
			},
		},
	}
	if err := df.Write(tmpFile); err != nil {
		t.Fatalf("failed to write test file: %v", err)
	}

	// Test: Adding a long comment that would exceed 140 chars should fail
	longNewComment := "This is another very long comment that when combined with the existing one will exceed the limit"
	result, err := CallsModify(CallsModifyInput{
		File:      tmpFile,
		Reviewer:  "tester",
		Filter:    "myfilter",
		Segment:   "10-15",
		Certainty: 80,
		Comment:   longNewComment,
	})

	if err == nil {
		t.Errorf("expected error for combined comment exceeding 140 chars, got nil")
	}
	if result.Error == "" {
		t.Errorf("expected error message, got empty")
	}

	// Verify original comment is preserved
	df2, err := utils.ParseDataFile(tmpFile)
	if err != nil {
		t.Fatalf("failed to parse file: %v", err)
	}
	if df2.Segments[0].Labels[0].Comment != existingComment {
		t.Errorf("original comment should be preserved, got %q", df2.Segments[0].Labels[0].Comment)
	}
}

func TestCallsModifyPreservesBookmarkOnOtherChange(t *testing.T) {
	// Create a temp .data file with a bookmark
	tmpDir := t.TempDir()
	tmpFile := filepath.Join(tmpDir, "test.data")

	df := &utils.DataFile{
		Meta: &utils.DataMeta{Operator: "test", Duration: 60},
		Segments: []*utils.Segment{
			{
				StartTime: 10.0,
				EndTime:   15.0,
				FreqLow:   100,
				FreqHigh:  5000,
				Labels: []*utils.Label{
					{Species: "Kiwi", Certainty: 80, Filter: "myfilter", Bookmark: true},
				},
			},
		},
	}
	if err := df.Write(tmpFile); err != nil {
		t.Fatalf("failed to write test file: %v", err)
	}

	// Change certainty (without passing --bookmark) - bookmark should be preserved
	result, err := CallsModify(CallsModifyInput{
		File:      tmpFile,
		Reviewer:  "tester",
		Filter:    "myfilter",
		Segment:   "10-15",
		Certainty: 100,
		// No Bookmark set
	})

	if err != nil {
		t.Errorf("unexpected error: %v", err)
	}
	if result.Bookmark != nil {
		t.Errorf("bookmark should not be in output when not changed, got %v", result.Bookmark)
	}

	// Verify bookmark is still true in the file
	df2, err := utils.ParseDataFile(tmpFile)
	if err != nil {
		t.Fatalf("failed to parse file: %v", err)
	}
	if !df2.Segments[0].Labels[0].Bookmark {
		t.Errorf("bookmark should still be true after changing certainty, got false")
	}
}

func TestCallsModifyInvalidSegment(t *testing.T) {
	tmpDir := t.TempDir()
	tmpFile := filepath.Join(tmpDir, "test.data")

	df := &utils.DataFile{
		Meta: &utils.DataMeta{Operator: "test", Duration: 60},
		Segments: []*utils.Segment{
			{
				StartTime: 10.0,
				EndTime:   15.0,
				FreqLow:   100,
				FreqHigh:  5000,
				Labels: []*utils.Label{
					{Species: "Kiwi", Certainty: 80, Filter: "myfilter"},
				},
			},
		},
	}
	if err := df.Write(tmpFile); err != nil {
		t.Fatalf("failed to write test file: %v", err)
	}

	// Test: Non-existent segment should error
	result, err := CallsModify(CallsModifyInput{
		File:      tmpFile,
		Reviewer:  "tester",
		Filter:    "myfilter",
		Segment:   "99-100",
		Certainty: 80,
	})

	if err == nil {
		t.Errorf("expected error for non-existent segment, got nil")
	}
	if result.Error == "" {
		t.Errorf("expected error message, got empty")
	}
}