package pso

import (
	"encoding/json"
	"net/http"
	"net/http/httptest"
	"strings"
	"testing"

	"system-altrak/internal/domain"

	"github.com/gofiber/fiber/v2"
)

type psoHandlerServiceMock struct {
	bulkVerifyIDs    []uint
	bulkVerifyBranch uint
	bulkVerifyUser   uint
	bulkVerifyErr    error

	deleteCalls  []uint
	deleteBranch uint
	deleteErr    error
}

func (m *psoHandlerServiceMock) ListOutstandingRecords(page, limit int, search string, branchID uint, startDate, endDate, aging string) ([]domain.OperationalRecord, int64, error) {
	return nil, 0, nil
}

func (m *psoHandlerServiceMock) UpdateRemark(id uint, remark string, branchID uint, role string) error {
	return nil
}

func (m *psoHandlerServiceMock) UpdateRecord(id uint, data map[string]interface{}, branchID uint, role string) error {
	return nil
}

func (m *psoHandlerServiceMock) GetByID(id uint, branchID uint) (*domain.OperationalRecord, error) {
	return nil, nil
}

func (m *psoHandlerServiceMock) Verify(id uint, branchID uint, userID uint) error {
	return nil
}

func (m *psoHandlerServiceMock) BulkVerify(ids []uint, branchID uint, userID uint) error {
	m.bulkVerifyIDs = append([]uint(nil), ids...)
	m.bulkVerifyBranch = branchID
	m.bulkVerifyUser = userID
	return m.bulkVerifyErr
}

func (m *psoHandlerServiceMock) ImportExcel(filePath string, branchID uint, jobID uint) (ImportExcelSummary, error) {
	return ImportExcelSummary{}, nil
}

func (m *psoHandlerServiceMock) ExportExcel(search string, cutoffStr string, branchID uint) ([]byte, error) {
	return nil, nil
}

func (m *psoHandlerServiceMock) ExportPdf(search string, cutoffStr string, branchID uint) ([]byte, error) {
	return nil, nil
}

func (m *psoHandlerServiceMock) Delete(id uint, branchID uint) error {
	m.deleteCalls = append(m.deleteCalls, id)
	m.deleteBranch = branchID
	return m.deleteErr
}

func buildPSOHandlerTestApp(h *Handler, userID uint, branchID uint, role string) *fiber.App {
	app := fiber.New()
	app.Use(func(c *fiber.Ctx) error {
		c.Locals("user_id", userID)
		c.Locals("current_branch_id", branchID)
		c.Locals("role", role)
		return c.Next()
	})
	app.Post("/pso/bulk-verify", h.BulkVerify)
	app.Delete("/pso/bulk-delete", h.BulkDelete)
	return app
}

func decodePSOHandlerBody(t *testing.T, resp *http.Response) map[string]interface{} {
	t.Helper()
	var body map[string]interface{}
	if err := json.NewDecoder(resp.Body).Decode(&body); err != nil {
		t.Fatalf("decode response failed: %v", err)
	}
	return body
}

func TestBulkVerifyAcceptsMultipleIDs(t *testing.T) {
	mock := &psoHandlerServiceMock{}
	h := NewHandler(mock, nil)
	app := buildPSOHandlerTestApp(h, 77, 9, "admin")

	req := httptest.NewRequest(http.MethodPost, "/pso/bulk-verify", strings.NewReader(`{"ids":[3,5,3,7]}`))
	req.Header.Set("Content-Type", "application/json")

	resp, err := app.Test(req)
	if err != nil {
		t.Fatalf("request failed: %v", err)
	}
	if resp.StatusCode != fiber.StatusOK {
		t.Fatalf("expected %d, got %d", fiber.StatusOK, resp.StatusCode)
	}
	if len(mock.bulkVerifyIDs) != 3 || mock.bulkVerifyIDs[0] != 3 || mock.bulkVerifyIDs[1] != 5 || mock.bulkVerifyIDs[2] != 7 {
		t.Fatalf("unexpected bulk verify IDs: %+v", mock.bulkVerifyIDs)
	}
	if mock.bulkVerifyBranch != 9 || mock.bulkVerifyUser != 77 {
		t.Fatalf("unexpected bulk verify context branch=%d user=%d", mock.bulkVerifyBranch, mock.bulkVerifyUser)
	}
	body := decodePSOHandlerBody(t, resp)
	if body["success"] != true {
		t.Fatalf("expected success=true, got=%v", body["success"])
	}
}

func TestBulkDeleteAcceptsMultipleIDs(t *testing.T) {
	mock := &psoHandlerServiceMock{}
	h := NewHandler(mock, nil)
	app := buildPSOHandlerTestApp(h, 5, 12, "superadmin")

	req := httptest.NewRequest(http.MethodDelete, "/pso/bulk-delete", strings.NewReader(`{"ids":[11,11,14,18]}`))
	req.Header.Set("Content-Type", "application/json")

	resp, err := app.Test(req)
	if err != nil {
		t.Fatalf("request failed: %v", err)
	}
	if resp.StatusCode != fiber.StatusOK {
		t.Fatalf("expected %d, got %d", fiber.StatusOK, resp.StatusCode)
	}
	if len(mock.deleteCalls) != 3 || mock.deleteCalls[0] != 11 || mock.deleteCalls[1] != 14 || mock.deleteCalls[2] != 18 {
		t.Fatalf("unexpected delete calls: %+v", mock.deleteCalls)
	}
	if mock.deleteBranch != 12 {
		t.Fatalf("unexpected delete branch: %d", mock.deleteBranch)
	}
	body := decodePSOHandlerBody(t, resp)
	if body["success"] != true {
		t.Fatalf("expected success=true, got=%v", body["success"])
	}
}

func TestBulkDeleteRejectsInvalidPayload(t *testing.T) {
	mock := &psoHandlerServiceMock{}
	h := NewHandler(mock, nil)
	app := buildPSOHandlerTestApp(h, 5, 12, "superadmin")

	req := httptest.NewRequest(http.MethodDelete, "/pso/bulk-delete", strings.NewReader(`{"ids":[]}`))
	req.Header.Set("Content-Type", "application/json")

	resp, err := app.Test(req)
	if err != nil {
		t.Fatalf("request failed: %v", err)
	}
	if resp.StatusCode != fiber.StatusBadRequest {
		t.Fatalf("expected %d, got %d", fiber.StatusBadRequest, resp.StatusCode)
	}
	if len(mock.deleteCalls) != 0 {
		t.Fatalf("did not expect delete calls on invalid payload, got=%d", len(mock.deleteCalls))
	}
}
