package handler

import (
	"bytes"
	"context"
	"io"
	"lune/talentscale/internal/domain"
	"mime/multipart"
	"net/http"
	"net/http/httptest"
	"strings"
	"testing"

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

// MockCandidateUsecase is a mock of the CandidateUsecase interface
type MockCandidateUsecase struct {
	mock.Mock
}

func (m *MockCandidateUsecase) Create(ctx context.Context, c *domain.Candidate) error {
	return m.Called(ctx, c).Error(0)
}

func (m *MockCandidateUsecase) GetByID(ctx context.Context, id uuid.UUID, companyID uuid.UUID) (*domain.Candidate, error) {
	args := m.Called(ctx, id, companyID)
	return args.Get(0).(*domain.Candidate), args.Error(1)
}

func (m *MockCandidateUsecase) List(ctx context.Context, companyID uuid.UUID, status string, search string, limit, offset int) ([]domain.Candidate, int, error) {
	args := m.Called(ctx, companyID, status, search, limit, offset)
	return args.Get(0).([]domain.Candidate), args.Int(1), args.Error(2)
}

func (m *MockCandidateUsecase) Update(ctx context.Context, c *domain.Candidate) error {
	return m.Called(ctx, c).Error(0)
}

func (m *MockCandidateUsecase) UpdateProfile(ctx context.Context, c *domain.Candidate) error {
	return m.Called(ctx, c).Error(0)
}

func (m *MockCandidateUsecase) Delete(ctx context.Context, id uuid.UUID, companyID uuid.UUID) error {
	return m.Called(ctx, id, companyID).Error(0)
}

// MockStorageService is a mock of the firebase.StorageService interface
type MockStorageService struct {
	mock.Mock
}

func (m *MockStorageService) UploadFile(ctx context.Context, file io.Reader, fileName string, contentType string) (string, error) {
	args := m.Called(ctx, file, fileName, contentType)
	return args.String(0), args.Error(1)
}

func TestProfileHandler_UpdateProfile(t *testing.T) {
	mockUsecase := new(MockCandidateUsecase)
	mockStorage := new(MockStorageService)
	h := NewProfileHandler(mockUsecase, mockStorage)
	candidateID := uuid.New()

	t.Run("Success", func(t *testing.T) {
		body := &bytes.Buffer{}
		writer := multipart.NewWriter(body)
		
		_ = writer.WriteField("phone", "08123456789")
		part, _ := writer.CreateFormFile("resume_file", "test.pdf")
		_, _ = io.WriteString(part, "fake content")
		_ = writer.Close()

		req := httptest.NewRequest(http.MethodPost, "/api/candidate/profile", body)
		req.Header.Set("Content-Type", writer.FormDataContentType())
		
		// Set context
		ctx := context.WithValue(req.Context(), "candidate_id", candidateID)
		req = req.WithContext(ctx)

		mockStorage.On("UploadFile", mock.Anything, mock.Anything, mock.MatchedBy(func(s string) bool {
			return strings.HasPrefix(s, "candidate/"+candidateID.String()+"/")
		}), mock.Anything).Return("https://firebase.com/test.pdf", nil)

		mockUsecase.On("UpdateProfile", mock.Anything, mock.MatchedBy(func(c *domain.Candidate) bool {
			return c.ID == candidateID && c.Phone == "08123456789" && c.ResumeFile == "https://firebase.com/test.pdf"
		})).Return(nil)

		w := httptest.NewRecorder()
		h.UpdateProfile(w, req)

		assert.Equal(t, http.StatusOK, w.Code)
		assert.Contains(t, w.Body.String(), "Profile updated successfully")
		mockUsecase.AssertExpectations(t)
	})

	t.Run("Invalid File Extension", func(t *testing.T) {
		body := &bytes.Buffer{}
		writer := multipart.NewWriter(body)
		
		_ = writer.WriteField("phone", "08123456789")
		part, _ := writer.CreateFormFile("resume_file", "test.exe")
		_, _ = io.WriteString(part, "fake content")
		_ = writer.Close()

		req := httptest.NewRequest(http.MethodPost, "/api/candidate/profile", body)
		req.Header.Set("Content-Type", writer.FormDataContentType())
		
		ctx := context.WithValue(req.Context(), "candidate_id", candidateID)
		req = req.WithContext(ctx)

		w := httptest.NewRecorder()
		h.UpdateProfile(w, req)

		assert.Equal(t, http.StatusBadRequest, w.Code)
		assert.Contains(t, w.Body.String(), "Invalid file format")
	})

	t.Run("Missing Phone", func(t *testing.T) {
		body := &bytes.Buffer{}
		writer := multipart.NewWriter(body)
		writer.Close()

		req := httptest.NewRequest(http.MethodPost, "/api/candidate/profile", body)
		req.Header.Set("Content-Type", writer.FormDataContentType())
		
		ctx := context.WithValue(req.Context(), "candidate_id", candidateID)
		req = req.WithContext(ctx)

		w := httptest.NewRecorder()
		h.UpdateProfile(w, req)

		assert.Equal(t, http.StatusBadRequest, w.Code)
		assert.Contains(t, w.Body.String(), "Phone number is required")
	})
}
