package handlers

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

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

type mockStorageService struct {
	generateUploadURLFunc   func(key string, contentType string, expiryMinutes int) (string, error)
	generateDownloadURLFunc func(key string, expiryMinutes int) (string, error)
	getPublicURLFunc        func(key string) string
	deleteObjectFunc        func(key string) error
}

func (m *mockStorageService) GenerateUploadURL(key string, contentType string, expiryMinutes int) (string, error) {
	if m.generateUploadURLFunc != nil {
		return m.generateUploadURLFunc(key, contentType, expiryMinutes)
	}
	return "https://s3.amazonaws.com/upload?sig=123", nil
}

func (m *mockStorageService) GenerateDownloadURL(key string, expiryMinutes int) (string, error) {
	if m.generateDownloadURLFunc != nil {
		return m.generateDownloadURLFunc(key, expiryMinutes)
	}
	return "https://s3.amazonaws.com/download?sig=123", nil
}

func (m *mockStorageService) GetPublicURL(key string) string {
	if m.getPublicURLFunc != nil {
		return m.getPublicURLFunc(key)
	}
	return "https://cdn.example.com/" + key
}

func (m *mockStorageService) DeleteObject(key string) error {
	if m.deleteObjectFunc != nil {
		return m.deleteObjectFunc(key)
	}
	return nil
}

func TestGenerateUploadURL_Success(t *testing.T) {
	mockStorage := &mockStorageService{}
	handler := NewStorageHandler(mockStorage)

	reqBody := map[string]string{
		"filename":    "test.jpg",
		"contentType": "image/jpeg",
		"folder":      "logos",
	}
	body, _ := json.Marshal(reqBody)
	req := httptest.NewRequest("POST", "/storage/upload-url", bytes.NewReader(body))
	rr := httptest.NewRecorder()

	handler.GenerateUploadURL(rr, req)

	assert.Equal(t, http.StatusOK, rr.Code)

	var resp map[string]interface{}
	json.Unmarshal(rr.Body.Bytes(), &resp)
	assert.Contains(t, resp, "uploadUrl")
	assert.Contains(t, resp, "key")
	assert.Contains(t, resp, "publicUrl")
}

func TestGenerateUploadURL_MissingFilename(t *testing.T) {
	mockStorage := &mockStorageService{}
	handler := NewStorageHandler(mockStorage)

	reqBody := map[string]string{
		"contentType": "image/jpeg",
	}
	body, _ := json.Marshal(reqBody)
	req := httptest.NewRequest("POST", "/storage/upload-url", bytes.NewReader(body))
	rr := httptest.NewRecorder()

	handler.GenerateUploadURL(rr, req)

	assert.Equal(t, http.StatusBadRequest, rr.Code)
}

func TestGenerateDownloadURL_Success(t *testing.T) {
	mockStorage := &mockStorageService{}
	handler := NewStorageHandler(mockStorage)

	reqBody := map[string]string{
		"key": "test/file.pdf",
	}
	body, _ := json.Marshal(reqBody)
	req := httptest.NewRequest("POST", "/storage/download-url", bytes.NewReader(body))
	rr := httptest.NewRecorder()

	handler.GenerateDownloadURL(rr, req)

	assert.Equal(t, http.StatusOK, rr.Code)

	var resp map[string]interface{}
	json.Unmarshal(rr.Body.Bytes(), &resp)
	assert.Contains(t, resp, "downloadUrl")
}

func TestDeleteFile_Success(t *testing.T) {
	mockStorage := &mockStorageService{}
	handler := NewStorageHandler(mockStorage)

	req := httptest.NewRequest("DELETE", "/storage/files?key=test.jpg", nil)
	rr := httptest.NewRecorder()

	handler.DeleteFile(rr, req)

	assert.Equal(t, http.StatusNoContent, rr.Code)
}

func TestDeleteFile_Error(t *testing.T) {
	mockStorage := &mockStorageService{
		deleteObjectFunc: func(key string) error {
			return errors.New("delete failed")
		},
	}
	handler := NewStorageHandler(mockStorage)

	req := httptest.NewRequest("DELETE", "/storage/files?key=test.jpg", nil)
	rr := httptest.NewRecorder()

	handler.DeleteFile(rr, req)

	assert.Equal(t, http.StatusInternalServerError, rr.Code)
}
