package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"os"
	"path/filepath"
	"testing"
	"time"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

func TestFSNotify_BulkFileDetection(t *testing.T) {
	setup := setupTestServer(t)
	t.Run("Detects multiple files added simultaneously", func(t *testing.T) {
		token := setup.Token
		tmpDir := t.TempDir()
		// Create library
		createLibReq := map[string]interface{}{
			"name": "bulk-test-library",
			"type": "ebooks",
		}
		libBody, _ := json.Marshal(createLibReq)
		libReq, _ := http.NewRequest("POST", setup.Server.URL+"/api/libraries", bytes.NewBuffer(libBody))
		libReq.Header.Set("Content-Type", "application/json")
		libReq.Header.Set("Authorization", "Bearer "+token)
		client := &http.Client{}
		libResp, err := client.Do(libReq)
		require.NoError(t, err)
		defer func(Body io.ReadCloser) {
			_ = Body.Close()
		}(libResp.Body)
		require.Equal(t, http.StatusCreated, libResp.StatusCode)
		var libResult map[string]interface{}
		err = json.NewDecoder(libResp.Body).Decode(&libResult)
		require.NoError(t, err)
		libraryID := libResult["id"].(string)
		// Add folder to library
		folderURL := fmt.Sprintf("%s/api/libraries/%s/folders", setup.Server.URL, libraryID)
		folderReq := map[string]interface{}{
			"folder_path": tmpDir,
		}
		folderBody, _ := json.Marshal(folderReq)
		folderHTTPReq, _ := http.NewRequest("POST", folderURL, bytes.NewBuffer(folderBody))
		folderHTTPReq.Header.Set("Content-Type", "application/json")
		folderHTTPReq.Header.Set("Authorization", "Bearer "+token)
		folderResp, err := client.Do(folderHTTPReq)
		require.NoError(t, err)
		defer func(Body io.ReadCloser) {
			_ = Body.Close()
		}(folderResp.Body)
		require.Equal(t, http.StatusCreated, folderResp.StatusCode, "Folder should be added to library")
		// Create 20 test files simultaneously
		for i := 0; i < 20; i++ {
			fileName := filepath.Join(tmpDir, fmt.Sprintf("book%d.epub", i))
			err := os.WriteFile(fileName, []byte(fmt.Sprintf("test %d", i)), 0644)
			require.NoError(t, err)
		}
		// Trigger library scan
		scanURL := fmt.Sprintf("%s/api/libraries/%s/scan", setup.Server.URL, libraryID)
		scanHTTPReq, _ := http.NewRequest("POST", scanURL, nil)
		scanHTTPReq.Header.Set("Authorization", "Bearer "+token)
		scanResp, err := client.Do(scanHTTPReq)
		require.NoError(t, err)
		defer func(Body io.ReadCloser) {
			_ = Body.Close()
		}(scanResp.Body)
		require.Equal(t, http.StatusAccepted, scanResp.StatusCode, "Scan should be accepted")
		var scanResponse map[string]interface{}
		err = json.NewDecoder(scanResp.Body).Decode(&scanResponse)
		require.NoError(t, err)
		jobID, ok := scanResponse["job_id"].(string)
		require.True(t, ok, "job_id should be string")
		require.NotEmpty(t, jobID, "job_id should not be empty")
		// Wait for scan job to complete
		time.Sleep(3 * time.Second)
		for i := 0; i < 30; i++ {
			if i > 0 {
				time.Sleep(1 * time.Second)
			}
			statusURL := fmt.Sprintf("%s/api/scanner/status/%s", setup.Server.URL, jobID)
			statusReq, _ := http.NewRequest("GET", statusURL, nil)
			statusReq.Header.Set("Authorization", "Bearer "+token)
			statusResp, err := client.Do(statusReq)
			require.NoError(t, err)

			if statusResp.StatusCode == http.StatusNotFound {
				_ = statusResp.Body.Close()
				break // Job completed
			}

			var status map[string]interface{}
			err = json.NewDecoder(statusResp.Body).Decode(&status)
			require.NoError(t, err)
			_ = statusResp.Body.Close()

			if status["status"] == "completed" || status["status"] == "failed" {
				_ = statusResp.Body.Close()
				break
			}
		}
		// Check items
		req, _ := http.NewRequest("GET", setup.Server.URL+"/api/libraries/"+libraryID+"/media-items", nil)
		req.Header.Set("Authorization", "Bearer "+token)
		itemsResp, err := client.Do(req)
		require.NoError(t, err)
		defer func(Body io.ReadCloser) {
			_ = Body.Close()
		}(itemsResp.Body)
		var itemsResult map[string]interface{}
		err = json.NewDecoder(itemsResp.Body).Decode(&itemsResult)
		require.NoError(t, err)
		items, ok := itemsResult["data"].([]interface{})
		if !ok || items == nil {
			items = []interface{}{} // Handle nil or wrong type
		}
		assert.GreaterOrEqual(t, len(items), 20, "Should detect all 20 files")
		// Cleanup
		deleteReq, _ := http.NewRequest("DELETE", setup.Server.URL+"/api/libraries/"+libraryID, nil)
		deleteReq.Header.Set("Authorization", "Bearer "+token)
		client.Do(deleteReq)
	})
}
