package main

import (
	"bytes"
	"encoding/json"
	"net/http/httptest"
	"testing"

	"github.com/google/uuid"
	"github.com/stretchr/testify/assert"
)

func TestKOReaderSyncProgress_RequestBody(t *testing.T) {
	t.Run("valid request body", func(t *testing.T) {
		reqBody := map[string]interface{}{
			"books": []map[string]interface{}{
				{
					"uuid":       "550e8400-e29b-41d4-a716-446655440000",
					"percentage": 0.45,
					"progress":   0.45,
					"chapter":    5,
				},
			},
			"sync_mode": "immediate",
		}

		body, err := json.Marshal(reqBody)
		assert.NoError(t, err)
		assert.Contains(t, string(body), "percentage")

		req := httptest.NewRequest("POST", "/api/sync/koreader/progress", bytes.NewReader(body))
		req.Header.Set("Content-Type", "application/json")

		assert.Equal(t, "POST", req.Method)
		assert.Equal(t, "/api/sync/koreader/progress", req.URL.Path)
	})

	t.Run("request with multiple books", func(t *testing.T) {
		reqBody := map[string]interface{}{
			"books": []map[string]interface{}{
				{
					"uuid":       "550e8400-e29b-41d4-a716-446655440000",
					"percentage": 0.25,
				},
				{
					"uuid":       "660e8400-e29b-41d4-a716-446655440001",
					"percentage": 0.50,
				},
			},
			"sync_mode": "checkpoint",
		}

		body, err := json.Marshal(reqBody)
		assert.NoError(t, err)

		var parsed map[string]interface{}
		err = json.Unmarshal(body, &parsed)
		assert.NoError(t, err)

		books := parsed["books"].([]interface{})
		assert.Len(t, books, 2)
	})

	t.Run("request with highlights and bookmarks", func(t *testing.T) {
		reqBody := map[string]interface{}{
			"book_uuid": "550e8400-e29b-41d4-a716-446655440000",
			"bookmarks": []map[string]interface{}{
				{
					"chapter": 3,
					"page":    45,
					"text":    "Bookmarked text",
				},
			},
			"highlights": []map[string]interface{}{
				{
					"chapter": 3,
					"page":    45,
					"text":    "highlighted text",
					"color":   "#ffff00",
				},
			},
		}

		body, err := json.Marshal(reqBody)
		assert.NoError(t, err)
		assert.Contains(t, string(body), "bookmarks")
		assert.Contains(t, string(body), "highlights")
	})
}

func TestKOReaderMetadataParsing(t *testing.T) {
	t.Run("parse progress data", func(t *testing.T) {
		progressData := map[string]interface{}{
			"percentage":       0.45,
			"chapter":          5,
			"epubcfi":          "epubcfi(/6/4/2:15)",
			"character":        int64(15432),
			"page":             89,
			"total_pages":      200,
			"chapter_progress": 0.234,
		}

		body, err := json.Marshal(progressData)
		assert.NoError(t, err)

		var parsed map[string]interface{}
		err = json.Unmarshal(body, &parsed)
		assert.NoError(t, err)

		assert.Equal(t, 0.45, parsed["percentage"])
		assert.Equal(t, "epubcfi(/6/4/2:15)", parsed["epubcfi"])
	})

	t.Run("parse annotation data", func(t *testing.T) {
		annotations := map[string]interface{}{
			"highlights": []map[string]interface{}{
				{
					"text":  "highlighted text",
					"pos0":  "epubcfi(/6/4/2:15)",
					"pos1":  "epubcfi(/6/4/2:20)",
					"color": "#ffff00",
				},
			},
			"notes": []map[string]interface{}{
				{
					"text": "My note",
					"pos0": "epubcfi(/6/4/2:15)",
				},
			},
		}

		body, err := json.Marshal(annotations)
		assert.NoError(t, err)

		var parsed map[string]interface{}
		err = json.Unmarshal(body, &parsed)
		assert.NoError(t, err)

		highlights := parsed["highlights"].([]interface{})
		assert.Len(t, highlights, 1)

		notes := parsed["notes"].([]interface{})
		assert.Len(t, notes, 1)
	})
}

func TestKOReaderResponseFormats(t *testing.T) {
	t.Run("sync progress response", func(t *testing.T) {
		response := map[string]interface{}{
			"sync_status":    "accepted",
			"books_synced":   1,
			"conflicts":      []interface{}{},
			"timestamp":      "2026-01-30T20:00:00Z",
			"device_updated": true,
		}

		body, err := json.Marshal(response)
		assert.NoError(t, err)

		var parsed map[string]interface{}
		err = json.Unmarshal(body, &parsed)
		assert.NoError(t, err)

		assert.Equal(t, "accepted", parsed["sync_status"])
		assert.Equal(t, float64(1), parsed["books_synced"])
	})

	t.Run("metadata response", func(t *testing.T) {
		response := map[string]interface{}{
			"uuid":    "550e8400-e29b-41d4-a716-446655440000",
			"title":   "Test Book",
			"authors": []string{"Test Author"},
			"progress": map[string]interface{}{
				"percentage": 0.45,
				"chapter":    5,
			},
			"annotations": map[string]interface{}{
				"highlights": []interface{}{},
				"notes":      []interface{}{},
			},
		}

		body, err := json.Marshal(response)
		assert.NoError(t, err)

		var parsed map[string]interface{}
		err = json.Unmarshal(body, &parsed)
		assert.NoError(t, err)

		assert.Equal(t, "Test Book", parsed["title"])
		assert.NotNil(t, parsed["progress"])
	})

	t.Run("library response", func(t *testing.T) {
		response := map[string]interface{}{
			"library_sync": []map[string]interface{}{
				{
					"uuid":            "550e8400-e29b-41d4-a716-446655440000",
					"title":           "Book 1",
					"author":          "Author 1",
					"percent_read":    45.0,
					"pages_remaining": 115,
					"bookmark_count":  3,
				},
			},
			"total_books": 1,
			"last_sync":   "2026-01-30T20:00:00Z",
		}

		body, err := json.Marshal(response)
		assert.NoError(t, err)

		var parsed map[string]interface{}
		err = json.Unmarshal(body, &parsed)
		assert.NoError(t, err)

		assert.Equal(t, float64(1), parsed["total_books"])
	})
}

func TestKOReaderErrorHandling(t *testing.T) {
	t.Run("invalid UUID format", func(t *testing.T) {
		req := httptest.NewRequest("GET", "/api/sync/koreader/metadata/invalid-uuid", nil)

		// This should fail UUID parsing
		_, err := uuid.Parse(req.URL.Path[len("/api/sync/koreader/metadata/"):])
		assert.Error(t, err)
	})

	t.Run("missing authorization header", func(t *testing.T) {
		req := httptest.NewRequest("POST", "/api/sync/koreader/progress", nil)
		req.Header.Set("Content-Type", "application/json")

		authHeader := req.Header.Get("Authorization")
		assert.Empty(t, authHeader)
	})

	t.Run("invalid percentage value", func(t *testing.T) {
		progressData := map[string]interface{}{
			"percentage": 1.5, // Invalid: > 1.0
		}

		body, err := json.Marshal(progressData)
		assert.NoError(t, err)

		var parsed map[string]interface{}
		err = json.Unmarshal(body, &parsed)
		assert.NoError(t, err)

		percentage := parsed["percentage"].(float64)
		assert.Greater(t, percentage, 1.0)
	})
}

func TestKOReaderDeviceMatching(t *testing.T) {
	t.Run("match by UUID", func(t *testing.T) {
		bookUUID := "550e8400-e29b-41d4-a716-446655440000"
		bookData := map[string]interface{}{
			"uuid":       bookUUID,
			"percentage": 0.45,
		}

		body, _ := json.Marshal(bookData)
		var parsed map[string]interface{}
		json.Unmarshal(body, &parsed)

		assert.Equal(t, bookUUID, parsed["uuid"])
	})

	t.Run("match by file path", func(t *testing.T) {
		bookData := map[string]interface{}{
			"file_path":  "/path/to/book.epub",
			"percentage": 0.45,
		}

		body, _ := json.Marshal(bookData)
		var parsed map[string]interface{}
		json.Unmarshal(body, &parsed)

		assert.Equal(t, "/path/to/book.epub", parsed["file_path"])
	})

	t.Run("match by title and author", func(t *testing.T) {
		bookData := map[string]interface{}{
			"title":      "Test Book",
			"authors":    []string{"Test Author"},
			"percentage": 0.45,
		}

		body, _ := json.Marshal(bookData)
		var parsed map[string]interface{}
		json.Unmarshal(body, &parsed)

		assert.Equal(t, "Test Book", parsed["title"])
		assert.NotNil(t, parsed["authors"])
	})
}
