package handlers

import (
	"bytes"
	"context"
	"errors"
	"io"
	"net/http"
	"testing"
	"time"

	"github.com/gofiber/fiber/v2"
	"gorm.io/gorm"

	airrescuechecklist "wucher/internal/domain/air_rescue_checklist"
	basedomain "wucher/internal/domain/base"
	"wucher/internal/shared/pkg/uuidv7"
)

type checklistServiceMock struct {
	listHEMSBasesRows []airrescuechecklist.HEMSBaseView
	getChecklistRow   *airrescuechecklist.ChecklistHeaderView

	createBulkCalled               bool
	updateChecklistWithItemsCalled bool
	reorderChecklistItemsCalled    bool
}

func (m *checklistServiceMock) CreateBulk(_ context.Context, _ []airrescuechecklist.ChecklistCreateInput) error {
	m.createBulkCalled = true
	return nil
}

func (m *checklistServiceMock) UpdateChecklist(_ context.Context, _ *airrescuechecklist.AirRescuerChecklist) error {
	return nil
}

func (m *checklistServiceMock) UpdateChecklistWithNewItems(_ context.Context, _ *airrescuechecklist.AirRescuerChecklist, _ []airrescuechecklist.AirRescuerChecklistItem) error {
	m.updateChecklistWithItemsCalled = true
	return nil
}

func (m *checklistServiceMock) DeleteChecklist(_ context.Context, _ []byte, _ []byte) error {
	return nil
}

func (m *checklistServiceMock) CreateChecklistItem(_ context.Context, _ *airrescuechecklist.AirRescuerChecklistItem) error {
	return nil
}

func (m *checklistServiceMock) CreateChecklistItems(_ context.Context, _ []byte, _ []airrescuechecklist.AirRescuerChecklistItem) error {
	return nil
}

func (m *checklistServiceMock) ReorderChecklistItems(_ context.Context, _ []byte, _ []airrescuechecklist.ChecklistItemReorderInput, _ []byte) error {
	m.reorderChecklistItemsCalled = true
	return nil
}

func (m *checklistServiceMock) UpdateChecklistItem(_ context.Context, _ *airrescuechecklist.AirRescuerChecklistItem) error {
	return nil
}

func (m *checklistServiceMock) DeleteChecklistItem(_ context.Context, _ []byte, _ []byte) error {
	return nil
}

func (m *checklistServiceMock) GetChecklistByID(_ context.Context, _ []byte) (*airrescuechecklist.ChecklistHeaderView, error) {
	return m.getChecklistRow, nil
}

func (m *checklistServiceMock) GetChecklistItemByID(_ context.Context, _ []byte) (*airrescuechecklist.ChecklistItemView, error) {
	return nil, nil
}

func (m *checklistServiceMock) ListChecklistHeaders(_ context.Context, _ airrescuechecklist.ChecklistHeaderFilter) ([]airrescuechecklist.ChecklistHeaderView, error) {
	return nil, nil
}

func (m *checklistServiceMock) ListChecklistItemsByChecklistIDs(_ context.Context, _ [][]byte) ([]airrescuechecklist.ChecklistItemView, error) {
	return nil, nil
}

func (m *checklistServiceMock) ListHEMSBases(_ context.Context, _ airrescuechecklist.HEMSBaseFilter) ([]airrescuechecklist.HEMSBaseView, error) {
	return m.listHEMSBasesRows, nil
}

func TestAirRescuerChecklistHandlerCreateRejectsCATScope(t *testing.T) {
	baseID := uuidv7.MustBytes()
	baseIDStr, _ := uuidv7.BytesToString(baseID)
	svc := &checklistServiceMock{
		listHEMSBasesRows: []airrescuechecklist.HEMSBaseView{{ID: baseID, BaseName: "Gallus 1 - Zurs Lech", BaseAbbreviation: "G1"}},
	}
	h := NewAirRescuerChecklistHandler(svc)
	app := fiber.New()
	app.Post("/api/v1/air-rescuer-checklist/create", h.Create)

	body := []byte(`{
		"data": {
			"type": "air_rescuer_checklist_create",
			"attributes": {
				"base_id": "` + baseIDStr + `",
				"checklists": [
					{"scope_code": "` + airrescuechecklist.AirRescuerChecklistScopeCAT + `", "title": "Overview Section"}
				]
			}
		}
	}`)

	resp, respBody := doChecklistJSONRequest(t, app, http.MethodPost, "/api/v1/air-rescuer-checklist/create", body)
	if resp.StatusCode != http.StatusUnprocessableEntity {
		t.Fatalf("expected 422, got %d", resp.StatusCode)
	}
	if !bytes.Contains(respBody, []byte("scope_code is invalid")) {
		t.Fatalf("expected scope validation error, got %s", string(respBody))
	}
	if svc.createBulkCalled {
		t.Fatalf("CreateBulk should not be called when CAT scope is rejected")
	}
}

func TestAirRescuerChecklistHandlerUpdateRejectsCATScope(t *testing.T) {
	checklistID := uuidv7.MustBytes()
	checklistIDStr, _ := uuidv7.BytesToString(checklistID)
	svc := &checklistServiceMock{
		getChecklistRow: &airrescuechecklist.ChecklistHeaderView{
			ID:        checklistID,
			ScopeCode: airrescuechecklist.AirRescuerChecklistScopeTA,
			Title:     "Cockpit Flugretter",
			Position:  1,
		},
	}
	h := NewAirRescuerChecklistHandler(svc)
	app := fiber.New()
	app.Patch("/api/v1/air-rescuer-checklist/update/:uuid", h.Update)

	body := []byte(`{
		"data": {
			"type": "air_rescuer_checklist_update",
			"id": "` + checklistIDStr + `",
			"attributes": {
				"scope_code": "` + airrescuechecklist.AirRescuerChecklistScopeCAT + `"
			}
		}
	}`)

	resp, respBody := doChecklistJSONRequest(t, app, http.MethodPatch, "/api/v1/air-rescuer-checklist/update/"+checklistIDStr, body)
	if resp.StatusCode != http.StatusUnprocessableEntity {
		t.Fatalf("expected 422, got %d", resp.StatusCode)
	}
	if !bytes.Contains(respBody, []byte("scope_code is invalid")) {
		t.Fatalf("expected scope validation error, got %s", string(respBody))
	}
	if svc.updateChecklistWithItemsCalled {
		t.Fatalf("UpdateChecklistWithNewItems should not be called when CAT scope is rejected")
	}
}

func doChecklistJSONRequest(t *testing.T, app *fiber.App, method, path string, body []byte) (*http.Response, []byte) {
	t.Helper()
	req, err := http.NewRequest(method, path, bytes.NewReader(body))
	if err != nil {
		t.Fatalf("new request: %v", err)
	}
	req.Header.Set("Content-Type", "application/json")
	resp, err := app.Test(req)
	if err != nil {
		t.Fatalf("app.Test: %v", err)
	}
	respBody, err := io.ReadAll(resp.Body)
	if err != nil {
		t.Fatalf("read body: %v", err)
	}
	return resp, respBody
}

type checklistServiceFullMock struct {
	createBulkFn                  func(context.Context, []airrescuechecklist.ChecklistCreateInput) error
	updateChecklistFn             func(context.Context, *airrescuechecklist.AirRescuerChecklist) error
	updateChecklistWithNewItemsFn func(context.Context, *airrescuechecklist.AirRescuerChecklist, []airrescuechecklist.AirRescuerChecklistItem) error
	deleteChecklistFn             func(context.Context, []byte, []byte) error
	createChecklistItemFn         func(context.Context, *airrescuechecklist.AirRescuerChecklistItem) error
	createChecklistItemsFn        func(context.Context, []byte, []airrescuechecklist.AirRescuerChecklistItem) error
	reorderChecklistItemsFn       func(context.Context, []byte, []airrescuechecklist.ChecklistItemReorderInput, []byte) error
	updateChecklistItemFn         func(context.Context, *airrescuechecklist.AirRescuerChecklistItem) error
	deleteChecklistItemFn         func(context.Context, []byte, []byte) error
	getChecklistByIDFn            func(context.Context, []byte) (*airrescuechecklist.ChecklistHeaderView, error)
	getChecklistItemByIDFn        func(context.Context, []byte) (*airrescuechecklist.ChecklistItemView, error)
	listChecklistHeadersFn        func(context.Context, airrescuechecklist.ChecklistHeaderFilter) ([]airrescuechecklist.ChecklistHeaderView, error)
	listChecklistItemsFn          func(context.Context, [][]byte) ([]airrescuechecklist.ChecklistItemView, error)
	listHEMSBasesFn               func(context.Context, airrescuechecklist.HEMSBaseFilter) ([]airrescuechecklist.HEMSBaseView, error)

	createBulkRows            []airrescuechecklist.ChecklistCreateInput
	updateChecklistWithRow    *airrescuechecklist.AirRescuerChecklist
	updateChecklistWithItems  []airrescuechecklist.AirRescuerChecklistItem
	createChecklistItemsArgID []byte
	createChecklistItemsRows  []airrescuechecklist.AirRescuerChecklistItem
	reorderChecklistArgID     []byte
	reorderChecklistRows      []airrescuechecklist.ChecklistItemReorderInput
	listHeaderFilter          airrescuechecklist.ChecklistHeaderFilter
	listBaseFilter            airrescuechecklist.HEMSBaseFilter
}

func (m *checklistServiceFullMock) CreateBulk(ctx context.Context, rows []airrescuechecklist.ChecklistCreateInput) error {
	m.createBulkRows = append([]airrescuechecklist.ChecklistCreateInput(nil), rows...)
	if m.createBulkFn != nil {
		return m.createBulkFn(ctx, rows)
	}
	return nil
}

func (m *checklistServiceFullMock) UpdateChecklist(ctx context.Context, row *airrescuechecklist.AirRescuerChecklist) error {
	if m.updateChecklistFn != nil {
		return m.updateChecklistFn(ctx, row)
	}
	return nil
}

func (m *checklistServiceFullMock) UpdateChecklistWithNewItems(ctx context.Context, row *airrescuechecklist.AirRescuerChecklist, newItems []airrescuechecklist.AirRescuerChecklistItem) error {
	m.updateChecklistWithRow = row
	m.updateChecklistWithItems = append([]airrescuechecklist.AirRescuerChecklistItem(nil), newItems...)
	if m.updateChecklistWithNewItemsFn != nil {
		return m.updateChecklistWithNewItemsFn(ctx, row, newItems)
	}
	return nil
}

func (m *checklistServiceFullMock) DeleteChecklist(ctx context.Context, id []byte, deletedBy []byte) error {
	if m.deleteChecklistFn != nil {
		return m.deleteChecklistFn(ctx, id, deletedBy)
	}
	return nil
}

func (m *checklistServiceFullMock) CreateChecklistItem(ctx context.Context, row *airrescuechecklist.AirRescuerChecklistItem) error {
	if m.createChecklistItemFn != nil {
		return m.createChecklistItemFn(ctx, row)
	}
	return nil
}

func (m *checklistServiceFullMock) CreateChecklistItems(ctx context.Context, checklistID []byte, rows []airrescuechecklist.AirRescuerChecklistItem) error {
	m.createChecklistItemsArgID = append([]byte(nil), checklistID...)
	m.createChecklistItemsRows = append([]airrescuechecklist.AirRescuerChecklistItem(nil), rows...)
	if m.createChecklistItemsFn != nil {
		return m.createChecklistItemsFn(ctx, checklistID, rows)
	}
	return nil
}

func (m *checklistServiceFullMock) ReorderChecklistItems(ctx context.Context, checklistID []byte, rows []airrescuechecklist.ChecklistItemReorderInput, updatedBy []byte) error {
	m.reorderChecklistArgID = append([]byte(nil), checklistID...)
	m.reorderChecklistRows = append([]airrescuechecklist.ChecklistItemReorderInput(nil), rows...)
	if m.reorderChecklistItemsFn != nil {
		return m.reorderChecklistItemsFn(ctx, checklistID, rows, updatedBy)
	}
	return nil
}

func (m *checklistServiceFullMock) UpdateChecklistItem(ctx context.Context, row *airrescuechecklist.AirRescuerChecklistItem) error {
	if m.updateChecklistItemFn != nil {
		return m.updateChecklistItemFn(ctx, row)
	}
	return nil
}

func (m *checklistServiceFullMock) DeleteChecklistItem(ctx context.Context, id []byte, deletedBy []byte) error {
	if m.deleteChecklistItemFn != nil {
		return m.deleteChecklistItemFn(ctx, id, deletedBy)
	}
	return nil
}

func (m *checklistServiceFullMock) GetChecklistByID(ctx context.Context, id []byte) (*airrescuechecklist.ChecklistHeaderView, error) {
	if m.getChecklistByIDFn != nil {
		return m.getChecklistByIDFn(ctx, id)
	}
	return nil, nil
}

func (m *checklistServiceFullMock) GetChecklistItemByID(ctx context.Context, id []byte) (*airrescuechecklist.ChecklistItemView, error) {
	if m.getChecklistItemByIDFn != nil {
		return m.getChecklistItemByIDFn(ctx, id)
	}
	return nil, nil
}

func (m *checklistServiceFullMock) ListChecklistHeaders(ctx context.Context, filter airrescuechecklist.ChecklistHeaderFilter) ([]airrescuechecklist.ChecklistHeaderView, error) {
	m.listHeaderFilter = filter
	if m.listChecklistHeadersFn != nil {
		return m.listChecklistHeadersFn(ctx, filter)
	}
	return []airrescuechecklist.ChecklistHeaderView{}, nil
}

func (m *checklistServiceFullMock) ListChecklistItemsByChecklistIDs(ctx context.Context, checklistIDs [][]byte) ([]airrescuechecklist.ChecklistItemView, error) {
	if m.listChecklistItemsFn != nil {
		return m.listChecklistItemsFn(ctx, checklistIDs)
	}
	return []airrescuechecklist.ChecklistItemView{}, nil
}

func (m *checklistServiceFullMock) ListHEMSBases(ctx context.Context, filter airrescuechecklist.HEMSBaseFilter) ([]airrescuechecklist.HEMSBaseView, error) {
	m.listBaseFilter = filter
	if m.listHEMSBasesFn != nil {
		return m.listHEMSBasesFn(ctx, filter)
	}
	return []airrescuechecklist.HEMSBaseView{}, nil
}

func newAirRescuerChecklistFullTestApp(h *AirRescuerChecklistHandler) *fiber.App {
	app := fiber.New()
	app.Post("/api/v1/air-rescuer-checklist/create", h.Create)
	app.Get("/api/v1/air-rescuer-checklist/get/:uuid", h.Get)
	app.Patch("/api/v1/air-rescuer-checklist/update/:uuid", h.Update)
	app.Delete("/api/v1/air-rescuer-checklist/delete/:uuid", h.Delete)
	app.Get("/api/v1/air-rescuer-checklist/get-all", h.List)
	app.Get("/api/v1/air-rescuer-checklist/get-all/dt", h.ListDatatable)
	app.Post("/api/v1/air-rescuer-checklist/:uuid/items/create", h.CreateItem)
	app.Patch("/api/v1/air-rescuer-checklist/:uuid/items/reorder", h.ReorderItems)
	app.Patch("/api/v1/air-rescuer-checklist/items/update/:item_uuid", h.UpdateItem)
	app.Delete("/api/v1/air-rescuer-checklist/items/delete/:item_uuid", h.DeleteItem)
	return app
}

func doChecklistJSONRequestFull(t *testing.T, app *fiber.App, method, path string, body []byte) (*http.Response, []byte) {
	t.Helper()
	req, err := http.NewRequest(method, path, bytes.NewReader(body))
	if err != nil {
		t.Fatalf("new request: %v", err)
	}
	req.Header.Set("Content-Type", "application/json")
	resp, err := app.Test(req)
	if err != nil {
		t.Fatalf("app.Test: %v", err)
	}
	raw, err := io.ReadAll(resp.Body)
	if err != nil {
		t.Fatalf("read body: %v", err)
	}
	return resp, raw
}

func mustUUIDStringChecklist(t *testing.T, id []byte) string {
	t.Helper()
	s, err := uuidv7.BytesToString(id)
	if err != nil {
		t.Fatalf("uuid to string: %v", err)
	}
	return s
}

func TestAirRescuerChecklistHandlerCreateBranches(t *testing.T) {
	baseID := uuidv7.MustBytes()
	baseIDStr := mustUUIDStringChecklist(t, baseID)

	validBody := []byte(`{
		"data": {
			"type": "air_rescuer_checklist_create",
			"attributes": {
				"base_id": "` + baseIDStr + `",
				"checklists": [{"scope_code":"TA","title":"Daily","position":1,"items":[{"name":"Battery","position":1}]}]
			}
		}
	}`)

	t.Run("invalid json", func(t *testing.T) {
		h := NewAirRescuerChecklistHandler(&checklistServiceFullMock{})
		app := newAirRescuerChecklistFullTestApp(h)
		resp, _ := doChecklistJSONRequestFull(t, app, http.MethodPost, "/api/v1/air-rescuer-checklist/create", []byte(`{`))
		if resp.StatusCode != http.StatusBadRequest {
			t.Fatalf("expected 400, got %d", resp.StatusCode)
		}
	})

	t.Run("validation failed", func(t *testing.T) {
		h := NewAirRescuerChecklistHandler(&checklistServiceFullMock{})
		app := newAirRescuerChecklistFullTestApp(h)
		resp, _ := doChecklistJSONRequestFull(t, app, http.MethodPost, "/api/v1/air-rescuer-checklist/create", []byte(`{"data":{"type":"wrong","attributes":{}}}`))
		if resp.StatusCode != http.StatusUnprocessableEntity {
			t.Fatalf("expected 422, got %d", resp.StatusCode)
		}
	})

	t.Run("base lookup error", func(t *testing.T) {
		svc := &checklistServiceFullMock{
			listHEMSBasesFn: func(context.Context, airrescuechecklist.HEMSBaseFilter) ([]airrescuechecklist.HEMSBaseView, error) {
				return nil, errors.New("db down")
			},
		}
		h := NewAirRescuerChecklistHandler(svc)
		app := newAirRescuerChecklistFullTestApp(h)
		resp, _ := doChecklistJSONRequestFull(t, app, http.MethodPost, "/api/v1/air-rescuer-checklist/create", validBody)
		if resp.StatusCode == http.StatusCreated {
			t.Fatalf("expected create to fail")
		}
	})

	t.Run("base not found", func(t *testing.T) {
		h := NewAirRescuerChecklistHandler(&checklistServiceFullMock{})
		app := newAirRescuerChecklistFullTestApp(h)
		resp, _ := doChecklistJSONRequestFull(t, app, http.MethodPost, "/api/v1/air-rescuer-checklist/create", validBody)
		if resp.StatusCode != http.StatusNotFound {
			t.Fatalf("expected 404, got %d", resp.StatusCode)
		}
	})

	t.Run("create service error", func(t *testing.T) {
		svc := &checklistServiceFullMock{
			listHEMSBasesFn: func(context.Context, airrescuechecklist.HEMSBaseFilter) ([]airrescuechecklist.HEMSBaseView, error) {
				return []airrescuechecklist.HEMSBaseView{{ID: baseID, BaseName: "Gallus 1 - Zurs Lech", BaseAbbreviation: "G1"}}, nil
			},
			createBulkFn: func(context.Context, []airrescuechecklist.ChecklistCreateInput) error {
				return errors.New("create failed")
			},
		}
		h := NewAirRescuerChecklistHandler(svc)
		app := newAirRescuerChecklistFullTestApp(h)
		resp, _ := doChecklistJSONRequestFull(t, app, http.MethodPost, "/api/v1/air-rescuer-checklist/create", validBody)
		if resp.StatusCode == http.StatusCreated {
			t.Fatalf("expected create failure")
		}
	})

	t.Run("load created resource error", func(t *testing.T) {
		checklistID := uuidv7.MustBytes()
		svc := &checklistServiceFullMock{
			listHEMSBasesFn: func(context.Context, airrescuechecklist.HEMSBaseFilter) ([]airrescuechecklist.HEMSBaseView, error) {
				return []airrescuechecklist.HEMSBaseView{{ID: baseID, BaseName: "Gallus 1 - Zurs Lech", BaseAbbreviation: "G1"}}, nil
			},
			createBulkFn: func(_ context.Context, rows []airrescuechecklist.ChecklistCreateInput) error {
				rows[0].Checklist.ID = append([]byte(nil), checklistID...)
				return nil
			},
			getChecklistByIDFn: func(context.Context, []byte) (*airrescuechecklist.ChecklistHeaderView, error) {
				return nil, errors.New("load failed")
			},
		}
		h := NewAirRescuerChecklistHandler(svc)
		app := newAirRescuerChecklistFullTestApp(h)
		resp, _ := doChecklistJSONRequestFull(t, app, http.MethodPost, "/api/v1/air-rescuer-checklist/create", validBody)
		if resp.StatusCode == http.StatusCreated {
			t.Fatalf("expected create response to fail when reloading resource fails")
		}
	})

	t.Run("success", func(t *testing.T) {
		checklistID := uuidv7.MustBytes()
		itemID := uuidv7.MustBytes()
		now := time.Now().UTC()

		svc := &checklistServiceFullMock{
			listHEMSBasesFn: func(context.Context, airrescuechecklist.HEMSBaseFilter) ([]airrescuechecklist.HEMSBaseView, error) {
				return []airrescuechecklist.HEMSBaseView{{ID: baseID, BaseName: "Gallus 1 - Zurs Lech", BaseAbbreviation: "G1"}}, nil
			},
			createBulkFn: func(_ context.Context, rows []airrescuechecklist.ChecklistCreateInput) error {
				rows[0].Checklist.ID = append([]byte(nil), checklistID...)
				rows[0].Items[0].ID = append([]byte(nil), itemID...)
				return nil
			},
			getChecklistByIDFn: func(_ context.Context, id []byte) (*airrescuechecklist.ChecklistHeaderView, error) {
				return &airrescuechecklist.ChecklistHeaderView{
					ID:               append([]byte(nil), id...),
					HEMSBaseID:       append([]byte(nil), baseID...),
					BaseName:         "Gallus 1 - Zurs Lech",
					BaseAbbreviation: "G1",
					ScopeCode:        airrescuechecklist.AirRescuerChecklistScopeTA,
					Title:            "Daily",
					Position:         1,
					CreatedAt:        now,
					UpdatedAt:        now,
				}, nil
			},
			listChecklistItemsFn: func(context.Context, [][]byte) ([]airrescuechecklist.ChecklistItemView, error) {
				return []airrescuechecklist.ChecklistItemView{{
					ID:          append([]byte(nil), itemID...),
					ChecklistID: append([]byte(nil), checklistID...),
					Name:        "Battery",
					Position:    1,
					CreatedAt:   now,
					UpdatedAt:   now,
				}}, nil
			},
		}
		h := NewAirRescuerChecklistHandler(svc)
		app := newAirRescuerChecklistFullTestApp(h)
		resp, body := doChecklistJSONRequestFull(t, app, http.MethodPost, "/api/v1/air-rescuer-checklist/create", validBody)
		if resp.StatusCode != http.StatusCreated {
			t.Fatalf("expected 201, got %d, body=%s", resp.StatusCode, string(body))
		}
		if len(svc.createBulkRows) != 1 {
			t.Fatalf("expected create bulk called once")
		}
		if !bytes.Contains(body, []byte(`"type":"air_rescuer_checklist"`)) {
			t.Fatalf("unexpected response body: %s", string(body))
		}
	})

	t.Run("success with english scope alias", func(t *testing.T) {
		checklistID := uuidv7.MustBytes()
		now := time.Now().UTC()

		aliasBody := []byte(`{
			"data": {
				"type": "air_rescuer_checklist_create",
				"attributes": {
					"base_id": "` + baseIDStr + `",
					"checklists": [{"scope_code":"TU","title":"Tuesday","position":1}]
				}
			}
		}`)

		svc := &checklistServiceFullMock{
			listHEMSBasesFn: func(context.Context, airrescuechecklist.HEMSBaseFilter) ([]airrescuechecklist.HEMSBaseView, error) {
				return []airrescuechecklist.HEMSBaseView{{ID: baseID, BaseName: "Gallus 1 - Zurs Lech", BaseAbbreviation: "G1"}}, nil
			},
			createBulkFn: func(_ context.Context, rows []airrescuechecklist.ChecklistCreateInput) error {
				rows[0].Checklist.ID = append([]byte(nil), checklistID...)
				return nil
			},
			getChecklistByIDFn: func(_ context.Context, id []byte) (*airrescuechecklist.ChecklistHeaderView, error) {
				return &airrescuechecklist.ChecklistHeaderView{
					ID:               append([]byte(nil), id...),
					HEMSBaseID:       append([]byte(nil), baseID...),
					BaseName:         "Gallus 1 - Zurs Lech",
					BaseAbbreviation: "G1",
					ScopeCode:        airrescuechecklist.AirRescuerChecklistScopeDI,
					Title:            "Tuesday",
					Position:         1,
					CreatedAt:        now,
					UpdatedAt:        now,
				}, nil
			},
			listChecklistItemsFn: func(context.Context, [][]byte) ([]airrescuechecklist.ChecklistItemView, error) {
				return []airrescuechecklist.ChecklistItemView{}, nil
			},
		}

		h := NewAirRescuerChecklistHandler(svc)
		app := newAirRescuerChecklistFullTestApp(h)
		resp, body := doChecklistJSONRequestFull(t, app, http.MethodPost, "/api/v1/air-rescuer-checklist/create", aliasBody)
		if resp.StatusCode != http.StatusCreated {
			t.Fatalf("expected 201, got %d, body=%s", resp.StatusCode, string(body))
		}
		if len(svc.createBulkRows) != 1 {
			t.Fatalf("expected create bulk called once")
		}
		if svc.createBulkRows[0].Checklist.ScopeCode != airrescuechecklist.AirRescuerChecklistScopeDI {
			t.Fatalf("expected TU alias to be normalized into DI, got %s", svc.createBulkRows[0].Checklist.ScopeCode)
		}
	})
}

func TestAirRescuerChecklistHandlerGetUpdateDeleteAndList(t *testing.T) {
	baseID := uuidv7.MustBytes()
	checklistID := uuidv7.MustBytes()
	itemID := uuidv7.MustBytes()
	now := time.Now().UTC()

	base := airrescuechecklist.HEMSBaseView{ID: baseID, BaseName: "Gallus 1 - Zurs Lech", BaseAbbreviation: "G1", Position: 1}
	header := airrescuechecklist.ChecklistHeaderView{
		ID:               checklistID,
		HEMSBaseID:       baseID,
		BaseName:         base.BaseName,
		BaseAbbreviation: base.BaseAbbreviation,
		ScopeCode:        airrescuechecklist.AirRescuerChecklistScopeTA,
		Title:            "Daily",
		Position:         1,
		CreatedAt:        now,
		UpdatedAt:        now,
	}
	item := airrescuechecklist.ChecklistItemView{
		ID:          itemID,
		ChecklistID: checklistID,
		Name:        "Battery",
		Position:    1,
		CreatedAt:   now,
		UpdatedAt:   now,
	}

	svc := &checklistServiceFullMock{
		getChecklistByIDFn: func(context.Context, []byte) (*airrescuechecklist.ChecklistHeaderView, error) {
			return &header, nil
		},
		listChecklistItemsFn: func(context.Context, [][]byte) ([]airrescuechecklist.ChecklistItemView, error) {
			return []airrescuechecklist.ChecklistItemView{item}, nil
		},
		updateChecklistWithNewItemsFn: func(context.Context, *airrescuechecklist.AirRescuerChecklist, []airrescuechecklist.AirRescuerChecklistItem) error {
			return nil
		},
		listHEMSBasesFn: func(context.Context, airrescuechecklist.HEMSBaseFilter) ([]airrescuechecklist.HEMSBaseView, error) {
			return []airrescuechecklist.HEMSBaseView{base}, nil
		},
		listChecklistHeadersFn: func(context.Context, airrescuechecklist.ChecklistHeaderFilter) ([]airrescuechecklist.ChecklistHeaderView, error) {
			return []airrescuechecklist.ChecklistHeaderView{header}, nil
		},
	}

	h := NewAirRescuerChecklistHandler(svc)
	app := newAirRescuerChecklistFullTestApp(h)
	checklistIDStr := mustUUIDStringChecklist(t, checklistID)

	t.Run("get success", func(t *testing.T) {
		resp, _ := doChecklistJSONRequestFull(t, app, http.MethodGet, "/api/v1/air-rescuer-checklist/get/"+checklistIDStr, nil)
		if resp.StatusCode != http.StatusOK {
			t.Fatalf("expected 200, got %d", resp.StatusCode)
		}
	})

	t.Run("update success with header and new_items", func(t *testing.T) {
		body := []byte(`{
			"data": {
				"type": "air_rescuer_checklist_update",
				"id": "` + checklistIDStr + `",
				"attributes": {
					"scope_code": "MO",
					"title": "Monday",
					"position": 2,
					"new_items": [{"name":"Radio","position":2}]
				}
			}
		}`)
		resp, raw := doChecklistJSONRequestFull(t, app, http.MethodPatch, "/api/v1/air-rescuer-checklist/update/"+checklistIDStr, body)
		if resp.StatusCode != http.StatusOK {
			t.Fatalf("expected 200, got %d body=%s", resp.StatusCode, string(raw))
		}
		if svc.updateChecklistWithRow == nil || svc.updateChecklistWithRow.ScopeCode != "MO" {
			t.Fatalf("expected header update row to be built")
		}
		if len(svc.updateChecklistWithItems) != 1 || svc.updateChecklistWithItems[0].Name != "Radio" {
			t.Fatalf("expected new_items append payload")
		}
	})

	t.Run("update success with english scope alias", func(t *testing.T) {
		body := []byte(`{
			"data": {
				"type": "air_rescuer_checklist_update",
				"id": "` + checklistIDStr + `",
				"attributes": {
					"scope_code": "THU"
				}
			}
		}`)
		resp, raw := doChecklistJSONRequestFull(t, app, http.MethodPatch, "/api/v1/air-rescuer-checklist/update/"+checklistIDStr, body)
		if resp.StatusCode != http.StatusOK {
			t.Fatalf("expected 200, got %d body=%s", resp.StatusCode, string(raw))
		}
		if svc.updateChecklistWithRow == nil || svc.updateChecklistWithRow.ScopeCode != airrescuechecklist.AirRescuerChecklistScopeDO {
			t.Fatalf("expected THU alias to be normalized into DO")
		}
	})

	t.Run("delete success", func(t *testing.T) {
		resp, _ := doChecklistJSONRequestFull(t, app, http.MethodDelete, "/api/v1/air-rescuer-checklist/delete/"+checklistIDStr, nil)
		if resp.StatusCode != http.StatusOK {
			t.Fatalf("expected 200, got %d", resp.StatusCode)
		}
	})

	t.Run("list success", func(t *testing.T) {
		resp, raw := doChecklistJSONRequestFull(t, app, http.MethodGet, "/api/v1/air-rescuer-checklist/get-all?scope_code=CAT", nil)
		if resp.StatusCode != http.StatusOK {
			t.Fatalf("expected 200, got %d", resp.StatusCode)
		}
		if !bytes.Contains(raw, []byte(`"total_bases"`)) {
			t.Fatalf("expected grouped list meta")
		}
	})

	t.Run("list success with persisted scope and base filter", func(t *testing.T) {
		resp, _ := doChecklistJSONRequestFull(t, app, http.MethodGet, "/api/v1/air-rescuer-checklist/get-all?base_id="+mustUUIDStringChecklist(t, baseID)+"&category_type=hems&scope_code=TA&base_name=gallus&base_abbreviation=g1", nil)
		if resp.StatusCode != http.StatusOK {
			t.Fatalf("expected 200, got %d", resp.StatusCode)
		}
		if !bytes.Equal(svc.listHeaderFilter.HEMSBaseID, baseID) {
			t.Fatalf("expected header filter base_id to be parsed")
		}
		if svc.listHeaderFilter.ScopeCode != airrescuechecklist.AirRescuerChecklistScopeTA {
			t.Fatalf("expected persisted scope filter to be parsed")
		}
		if !bytes.Equal(svc.listBaseFilter.HEMSBaseID, baseID) {
			t.Fatalf("expected base filter base_id to be parsed")
		}
		if svc.listHeaderFilter.CategoryType != basedomain.CategoryKeyHEMS || svc.listBaseFilter.CategoryType != basedomain.CategoryKeyHEMS {
			t.Fatalf("expected category_type filter to be parsed as hems")
		}
	})

	t.Run("list success with english scope alias", func(t *testing.T) {
		resp, _ := doChecklistJSONRequestFull(t, app, http.MethodGet, "/api/v1/air-rescuer-checklist/get-all?scope_code=SU", nil)
		if resp.StatusCode != http.StatusOK {
			t.Fatalf("expected 200, got %d", resp.StatusCode)
		}
		if svc.listHeaderFilter.ScopeCode != airrescuechecklist.AirRescuerChecklistScopeSO {
			t.Fatalf("expected SU alias to be normalized into SO")
		}
	})

	t.Run("list datatable success", func(t *testing.T) {
		resp, raw := doChecklistJSONRequestFull(t, app, http.MethodGet, "/api/v1/air-rescuer-checklist/get-all/dt?page=0&size=0&limit=200&draw=7", nil)
		if resp.StatusCode != http.StatusOK {
			t.Fatalf("expected 200, got %d", resp.StatusCode)
		}
		if !bytes.Contains(raw, []byte(`"records_total"`)) {
			t.Fatalf("expected datatable meta")
		}
	})

	t.Run("list invalid category_type", func(t *testing.T) {
		resp, _ := doChecklistJSONRequestFull(t, app, http.MethodGet, "/api/v1/air-rescuer-checklist/get-all?category_type=oops", nil)
		if resp.StatusCode != http.StatusUnprocessableEntity {
			t.Fatalf("expected 422, got %d", resp.StatusCode)
		}
	})

	t.Run("list accepts base_category alias", func(t *testing.T) {
		resp, _ := doChecklistJSONRequestFull(t, app, http.MethodGet, "/api/v1/air-rescuer-checklist/get-all?base_category=hems", nil)
		if resp.StatusCode != http.StatusOK {
			t.Fatalf("expected 200, got %d", resp.StatusCode)
		}
		if svc.listHeaderFilter.CategoryType != basedomain.CategoryKeyHEMS || svc.listBaseFilter.CategoryType != basedomain.CategoryKeyHEMS {
			t.Fatalf("expected base_category alias parsed as hems")
		}
	})
}

func TestAirRescuerChecklistHandlerItemEndpoints(t *testing.T) {
	checklistID := uuidv7.MustBytes()
	itemID := uuidv7.MustBytes()
	now := time.Now().UTC()

	itemIDStr := mustUUIDStringChecklist(t, itemID)
	checklistIDStr := mustUUIDStringChecklist(t, checklistID)

	createdItemCall := 0
	svc := &checklistServiceFullMock{
		createChecklistItemsFn: func(_ context.Context, _ []byte, rows []airrescuechecklist.AirRescuerChecklistItem) error {
			for i := range rows {
				rows[i].ID = uuidv7.MustBytes()
			}
			return nil
		},
		getChecklistItemByIDFn: func(_ context.Context, _ []byte) (*airrescuechecklist.ChecklistItemView, error) {
			createdItemCall++
			if createdItemCall == 1 {
				return nil, nil
			}
			return &airrescuechecklist.ChecklistItemView{
				ID:          itemID,
				ChecklistID: checklistID,
				Name:        "Battery",
				Position:    1,
				CreatedAt:   now,
				UpdatedAt:   now,
			}, nil
		},
		getChecklistByIDFn: func(_ context.Context, id []byte) (*airrescuechecklist.ChecklistHeaderView, error) {
			return &airrescuechecklist.ChecklistHeaderView{
				ID:               append([]byte(nil), id...),
				HEMSBaseID:       uuidv7.MustBytes(),
				BaseName:         "Gallus 1 - Zurs Lech",
				BaseAbbreviation: "G1",
				ScopeCode:        airrescuechecklist.AirRescuerChecklistScopeTA,
				Title:            "Daily",
				Position:         1,
				CreatedAt:        now,
				UpdatedAt:        now,
			}, nil
		},
		listChecklistItemsFn: func(_ context.Context, _ [][]byte) ([]airrescuechecklist.ChecklistItemView, error) {
			return []airrescuechecklist.ChecklistItemView{{
				ID:          itemID,
				ChecklistID: checklistID,
				Name:        "Battery",
				Position:    1,
				CreatedAt:   now,
				UpdatedAt:   now,
			}}, nil
		},
		updateChecklistItemFn: func(context.Context, *airrescuechecklist.AirRescuerChecklistItem) error {
			return nil
		},
	}
	h := NewAirRescuerChecklistHandler(svc)
	app := newAirRescuerChecklistFullTestApp(h)

	t.Run("create item bulk success with fallback and fetched item", func(t *testing.T) {
		body := []byte(`{
			"data": {
				"type": "air_rescuer_checklist_item_create",
				"attributes": {
					"items": [{"name":"Radio","position":2},{"name":"Battery","position":1}]
				}
			}
		}`)
		resp, raw := doChecklistJSONRequestFull(t, app, http.MethodPost, "/api/v1/air-rescuer-checklist/"+checklistIDStr+"/items/create", body)
		if resp.StatusCode != http.StatusCreated {
			t.Fatalf("expected 201, got %d body=%s", resp.StatusCode, string(raw))
		}
		if !bytes.Equal(svc.createChecklistItemsArgID, checklistID) {
			t.Fatalf("expected checklist id taken from path")
		}
		if len(svc.createChecklistItemsRows) != 2 {
			t.Fatalf("expected 2 item rows")
		}
	})

	t.Run("update item success", func(t *testing.T) {
		body := []byte(`{
			"data": {
				"type": "air_rescuer_checklist_item_update",
				"id": "` + itemIDStr + `",
				"attributes": {"name":"Battery Updated","position":3}
			}
		}`)
		resp, raw := doChecklistJSONRequestFull(t, app, http.MethodPatch, "/api/v1/air-rescuer-checklist/items/update/"+itemIDStr, body)
		if resp.StatusCode != http.StatusOK {
			t.Fatalf("expected 200, got %d body=%s", resp.StatusCode, string(raw))
		}
	})

	t.Run("reorder items success", func(t *testing.T) {
		body := []byte(`{
			"data": {
				"type": "air_rescuer_checklist_item_reorder",
				"attributes": {
					"items": [
						{"item_uuid":"` + itemIDStr + `","position":2},
						{"item_uuid":"` + mustUUIDStringChecklist(t, uuidv7.MustBytes()) + `","position":1}
					]
				}
			}
		}`)
		resp, raw := doChecklistJSONRequestFull(t, app, http.MethodPatch, "/api/v1/air-rescuer-checklist/"+checklistIDStr+"/items/reorder", body)
		if resp.StatusCode != http.StatusOK {
			t.Fatalf("expected 200, got %d body=%s", resp.StatusCode, string(raw))
		}
		if !bytes.Equal(svc.reorderChecklistArgID, checklistID) {
			t.Fatalf("expected reorder checklist id from path")
		}
		if len(svc.reorderChecklistRows) != 2 {
			t.Fatalf("expected 2 reorder rows")
		}
	})

	t.Run("delete item success", func(t *testing.T) {
		resp, _ := doChecklistJSONRequestFull(t, app, http.MethodDelete, "/api/v1/air-rescuer-checklist/items/delete/"+itemIDStr, nil)
		if resp.StatusCode != http.StatusOK {
			t.Fatalf("expected 200, got %d", resp.StatusCode)
		}
	})
}

func TestAirRescuerChecklistHandlerErrorBranches(t *testing.T) {
	baseID := uuidv7.MustBytes()
	baseIDStr := mustUUIDStringChecklist(t, baseID)
	checklistID := uuidv7.MustBytes()
	checklistIDStr := mustUUIDStringChecklist(t, checklistID)
	itemID := uuidv7.MustBytes()
	itemIDStr := mustUUIDStringChecklist(t, itemID)

	t.Run("get invalid uuid", func(t *testing.T) {
		app := newAirRescuerChecklistFullTestApp(NewAirRescuerChecklistHandler(&checklistServiceFullMock{}))
		resp, _ := doChecklistJSONRequestFull(t, app, http.MethodGet, "/api/v1/air-rescuer-checklist/get/not-uuid", nil)
		if resp.StatusCode != http.StatusUnprocessableEntity {
			t.Fatalf("expected 422, got %d", resp.StatusCode)
		}
	})

	t.Run("get not found and service error", func(t *testing.T) {
		svcNotFound := &checklistServiceFullMock{}
		app := newAirRescuerChecklistFullTestApp(NewAirRescuerChecklistHandler(svcNotFound))
		resp, _ := doChecklistJSONRequestFull(t, app, http.MethodGet, "/api/v1/air-rescuer-checklist/get/"+checklistIDStr, nil)
		if resp.StatusCode != http.StatusNotFound {
			t.Fatalf("expected 404, got %d", resp.StatusCode)
		}

		svcErr := &checklistServiceFullMock{
			getChecklistByIDFn: func(context.Context, []byte) (*airrescuechecklist.ChecklistHeaderView, error) {
				return nil, errors.New("boom")
			},
		}
		app = newAirRescuerChecklistFullTestApp(NewAirRescuerChecklistHandler(svcErr))
		resp, _ = doChecklistJSONRequestFull(t, app, http.MethodGet, "/api/v1/air-rescuer-checklist/get/"+checklistIDStr, nil)
		if resp.StatusCode == http.StatusOK {
			t.Fatalf("expected non-200 for service error")
		}
	})

	t.Run("update validation and failure branches", func(t *testing.T) {
		appGetErr := newAirRescuerChecklistFullTestApp(NewAirRescuerChecklistHandler(&checklistServiceFullMock{
			getChecklistByIDFn: func(context.Context, []byte) (*airrescuechecklist.ChecklistHeaderView, error) {
				return nil, errors.New("get failed")
			},
		}))
		resp, _ := doChecklistJSONRequestFull(t, appGetErr, http.MethodPatch, "/api/v1/air-rescuer-checklist/update/"+checklistIDStr, []byte(`{"data":{"type":"air_rescuer_checklist_update","attributes":{"title":"x"}}}`))
		if resp.StatusCode == http.StatusOK {
			t.Fatalf("expected update to fail when loading existing checklist fails")
		}

		appNotFound := newAirRescuerChecklistFullTestApp(NewAirRescuerChecklistHandler(&checklistServiceFullMock{}))
		resp, _ = doChecklistJSONRequestFull(t, appNotFound, http.MethodPatch, "/api/v1/air-rescuer-checklist/update/"+checklistIDStr, []byte(`{"data":{"type":"air_rescuer_checklist_update","attributes":{"title":"x"}}}`))
		if resp.StatusCode != http.StatusNotFound {
			t.Fatalf("expected 404 when checklist not found, got %d", resp.StatusCode)
		}

		svc := &checklistServiceFullMock{
			getChecklistByIDFn: func(context.Context, []byte) (*airrescuechecklist.ChecklistHeaderView, error) {
				return &airrescuechecklist.ChecklistHeaderView{ID: checklistID, ScopeCode: "TA", Title: "Old", Position: 1}, nil
			},
			updateChecklistWithNewItemsFn: func(context.Context, *airrescuechecklist.AirRescuerChecklist, []airrescuechecklist.AirRescuerChecklistItem) error {
				return gorm.ErrRecordNotFound
			},
		}
		app := newAirRescuerChecklistFullTestApp(NewAirRescuerChecklistHandler(svc))

		resp, _ = doChecklistJSONRequestFull(t, app, http.MethodPatch, "/api/v1/air-rescuer-checklist/update/not-uuid", nil)
		if resp.StatusCode != http.StatusUnprocessableEntity {
			t.Fatalf("expected 422 for invalid path uuid, got %d", resp.StatusCode)
		}

		resp, _ = doChecklistJSONRequestFull(t, app, http.MethodPatch, "/api/v1/air-rescuer-checklist/update/"+checklistIDStr, []byte(`{`))
		if resp.StatusCode != http.StatusBadRequest {
			t.Fatalf("expected 400 for invalid json, got %d", resp.StatusCode)
		}

		resp, _ = doChecklistJSONRequestFull(t, app, http.MethodPatch, "/api/v1/air-rescuer-checklist/update/"+checklistIDStr, []byte(`{"data":{"type":"wrong","attributes":{}}}`))
		if resp.StatusCode != http.StatusUnprocessableEntity {
			t.Fatalf("expected 422 for validator, got %d", resp.StatusCode)
		}

		resp, _ = doChecklistJSONRequestFull(t, app, http.MethodPatch, "/api/v1/air-rescuer-checklist/update/"+checklistIDStr, []byte(`{"data":{"type":"air_rescuer_checklist_update","id":"bad-uuid","attributes":{"title":"x"}}}`))
		if resp.StatusCode != http.StatusUnprocessableEntity {
			t.Fatalf("expected 422 for invalid body id, got %d", resp.StatusCode)
		}

		resp, _ = doChecklistJSONRequestFull(t, app, http.MethodPatch, "/api/v1/air-rescuer-checklist/update/"+checklistIDStr, []byte(`{"data":{"type":"air_rescuer_checklist_update","id":"`+mustUUIDStringChecklist(t, uuidv7.MustBytes())+`","attributes":{"title":"x"}}}`))
		if resp.StatusCode != http.StatusUnprocessableEntity {
			t.Fatalf("expected 422 for id mismatch, got %d", resp.StatusCode)
		}

		resp, _ = doChecklistJSONRequestFull(t, app, http.MethodPatch, "/api/v1/air-rescuer-checklist/update/"+checklistIDStr, []byte(`{"data":{"type":"air_rescuer_checklist_update","attributes":{"new_items":[]}}}`))
		if resp.StatusCode != http.StatusUnprocessableEntity {
			t.Fatalf("expected 422 for empty new_items, got %d", resp.StatusCode)
		}

		resp, _ = doChecklistJSONRequestFull(t, app, http.MethodPatch, "/api/v1/air-rescuer-checklist/update/"+checklistIDStr, []byte(`{"data":{"type":"air_rescuer_checklist_update","attributes":{}}}`))
		if resp.StatusCode != http.StatusUnprocessableEntity {
			t.Fatalf("expected 422 for empty attrs, got %d", resp.StatusCode)
		}

		resp, _ = doChecklistJSONRequestFull(t, app, http.MethodPatch, "/api/v1/air-rescuer-checklist/update/"+checklistIDStr, []byte(`{"data":{"type":"air_rescuer_checklist_update","attributes":{"scope_code":" "}}}`))
		if resp.StatusCode != http.StatusUnprocessableEntity {
			t.Fatalf("expected 422 for blank scope, got %d", resp.StatusCode)
		}

		resp, _ = doChecklistJSONRequestFull(t, app, http.MethodPatch, "/api/v1/air-rescuer-checklist/update/"+checklistIDStr, []byte(`{"data":{"type":"air_rescuer_checklist_update","attributes":{"scope_code":"CAT"}}}`))
		if resp.StatusCode != http.StatusUnprocessableEntity {
			t.Fatalf("expected 422 for CAT scope, got %d", resp.StatusCode)
		}

		resp, _ = doChecklistJSONRequestFull(t, app, http.MethodPatch, "/api/v1/air-rescuer-checklist/update/"+checklistIDStr, []byte(`{"data":{"type":"air_rescuer_checklist_update","attributes":{"title":" "}}}`))
		if resp.StatusCode != http.StatusUnprocessableEntity {
			t.Fatalf("expected 422 for blank title, got %d", resp.StatusCode)
		}

		resp, _ = doChecklistJSONRequestFull(t, app, http.MethodPatch, "/api/v1/air-rescuer-checklist/update/"+checklistIDStr, []byte(`{"data":{"type":"air_rescuer_checklist_update","attributes":{"new_items":[{"name":" "}]}}}`))
		if resp.StatusCode != http.StatusUnprocessableEntity {
			t.Fatalf("expected 422 for blank new item name, got %d", resp.StatusCode)
		}

		resp, _ = doChecklistJSONRequestFull(t, app, http.MethodPatch, "/api/v1/air-rescuer-checklist/update/"+checklistIDStr, []byte(`{"data":{"type":"air_rescuer_checklist_update","attributes":{"title":"Updated"}}}`))
		if resp.StatusCode != http.StatusNotFound {
			t.Fatalf("expected 404 from service not found, got %d", resp.StatusCode)
		}
	})

	t.Run("delete branches", func(t *testing.T) {
		svc := &checklistServiceFullMock{
			deleteChecklistFn: func(context.Context, []byte, []byte) error { return gorm.ErrRecordNotFound },
		}
		app := newAirRescuerChecklistFullTestApp(NewAirRescuerChecklistHandler(svc))
		resp, _ := doChecklistJSONRequestFull(t, app, http.MethodDelete, "/api/v1/air-rescuer-checklist/delete/not-uuid", nil)
		if resp.StatusCode != http.StatusUnprocessableEntity {
			t.Fatalf("expected 422 invalid uuid, got %d", resp.StatusCode)
		}
		resp, _ = doChecklistJSONRequestFull(t, app, http.MethodDelete, "/api/v1/air-rescuer-checklist/delete/"+checklistIDStr, nil)
		if resp.StatusCode != http.StatusNotFound {
			t.Fatalf("expected 404 from delete service, got %d", resp.StatusCode)
		}
	})

	t.Run("list invalid filters and service failures", func(t *testing.T) {
		svc := &checklistServiceFullMock{
			listHEMSBasesFn: func(context.Context, airrescuechecklist.HEMSBaseFilter) ([]airrescuechecklist.HEMSBaseView, error) {
				return nil, errors.New("base list failed")
			},
		}
		app := newAirRescuerChecklistFullTestApp(NewAirRescuerChecklistHandler(svc))

		resp, _ := doChecklistJSONRequestFull(t, app, http.MethodGet, "/api/v1/air-rescuer-checklist/get-all?base_id=bad", nil)
		if resp.StatusCode == http.StatusOK {
			t.Fatalf("expected invalid base id filter to fail, got %d", resp.StatusCode)
		}
		resp, _ = doChecklistJSONRequestFull(t, app, http.MethodGet, "/api/v1/air-rescuer-checklist/get-all?scope_code=bad", nil)
		if resp.StatusCode == http.StatusOK {
			t.Fatalf("expected invalid scope filter to fail, got %d", resp.StatusCode)
		}
		resp, _ = doChecklistJSONRequestFull(t, app, http.MethodGet, "/api/v1/air-rescuer-checklist/get-all", nil)
		if resp.StatusCode == http.StatusOK {
			t.Fatalf("expected list service failure")
		}
	})

	t.Run("list datatable error and length fallback", func(t *testing.T) {
		svcErr := &checklistServiceFullMock{
			listHEMSBasesFn: func(context.Context, airrescuechecklist.HEMSBaseFilter) ([]airrescuechecklist.HEMSBaseView, error) {
				return nil, errors.New("base list failed")
			},
		}
		app := newAirRescuerChecklistFullTestApp(NewAirRescuerChecklistHandler(svcErr))
		resp, _ := doChecklistJSONRequestFull(t, app, http.MethodGet, "/api/v1/air-rescuer-checklist/get-all/dt?base_id=bad", nil)
		if resp.StatusCode == http.StatusOK {
			t.Fatalf("expected invalid datatable filter to fail")
		}

		resp, _ = doChecklistJSONRequestFull(t, app, http.MethodGet, "/api/v1/air-rescuer-checklist/get-all/dt?scope_code=bad", nil)
		if resp.StatusCode == http.StatusOK {
			t.Fatalf("expected invalid datatable scope filter to fail")
		}

		resp, _ = doChecklistJSONRequestFull(t, app, http.MethodGet, "/api/v1/air-rescuer-checklist/get-all/dt", nil)
		if resp.StatusCode == http.StatusOK {
			t.Fatalf("expected datatable list failure")
		}

		base := airrescuechecklist.HEMSBaseView{ID: baseID, BaseName: "Gallus 1", BaseAbbreviation: "G1", Position: 1}
		svcOK := &checklistServiceFullMock{
			listHEMSBasesFn: func(context.Context, airrescuechecklist.HEMSBaseFilter) ([]airrescuechecklist.HEMSBaseView, error) {
				return []airrescuechecklist.HEMSBaseView{base}, nil
			},
			listChecklistHeadersFn: func(context.Context, airrescuechecklist.ChecklistHeaderFilter) ([]airrescuechecklist.ChecklistHeaderView, error) {
				return nil, nil
			},
		}
		app = newAirRescuerChecklistFullTestApp(NewAirRescuerChecklistHandler(svcOK))
		resp, body := doChecklistJSONRequestFull(t, app, http.MethodGet, "/api/v1/air-rescuer-checklist/get-all/dt?page=0&limit=-1&size=0&draw=1", nil)
		if resp.StatusCode != http.StatusOK {
			t.Fatalf("expected 200 datatable fallback, got %d", resp.StatusCode)
		}
		if !bytes.Contains(body, []byte(`"records_filtered"`)) {
			t.Fatalf("expected datatable meta in response")
		}
	})

	t.Run("create item failures", func(t *testing.T) {
		app := newAirRescuerChecklistFullTestApp(NewAirRescuerChecklistHandler(&checklistServiceFullMock{}))
		resp, _ := doChecklistJSONRequestFull(t, app, http.MethodPost, "/api/v1/air-rescuer-checklist/not-uuid/items/create", nil)
		if resp.StatusCode != http.StatusUnprocessableEntity {
			t.Fatalf("expected 422 invalid path uuid, got %d", resp.StatusCode)
		}
		resp, _ = doChecklistJSONRequestFull(t, app, http.MethodPost, "/api/v1/air-rescuer-checklist/"+checklistIDStr+"/items/create", []byte(`{`))
		if resp.StatusCode != http.StatusBadRequest {
			t.Fatalf("expected 400 invalid json, got %d", resp.StatusCode)
		}
		resp, _ = doChecklistJSONRequestFull(t, app, http.MethodPost, "/api/v1/air-rescuer-checklist/"+checklistIDStr+"/items/create", []byte(`{"data":{"type":"wrong","attributes":{}}}`))
		if resp.StatusCode != http.StatusUnprocessableEntity {
			t.Fatalf("expected 422 validator, got %d", resp.StatusCode)
		}
		resp, _ = doChecklistJSONRequestFull(t, app, http.MethodPost, "/api/v1/air-rescuer-checklist/"+checklistIDStr+"/items/create", []byte(`{"data":{"type":"air_rescuer_checklist_item_create","attributes":{"items":[]}}}`))
		if resp.StatusCode != http.StatusUnprocessableEntity {
			t.Fatalf("expected 422 empty items, got %d", resp.StatusCode)
		}
		resp, _ = doChecklistJSONRequestFull(t, app, http.MethodPost, "/api/v1/air-rescuer-checklist/"+checklistIDStr+"/items/create", []byte(`{"data":{"type":"air_rescuer_checklist_item_create","attributes":{"items":[{"name":" "}]}}}`))
		if resp.StatusCode != http.StatusUnprocessableEntity {
			t.Fatalf("expected 422 blank name, got %d", resp.StatusCode)
		}

		svcErr := &checklistServiceFullMock{
			createChecklistItemsFn: func(context.Context, []byte, []airrescuechecklist.AirRescuerChecklistItem) error {
				return gorm.ErrRecordNotFound
			},
		}
		app = newAirRescuerChecklistFullTestApp(NewAirRescuerChecklistHandler(svcErr))
		resp, _ = doChecklistJSONRequestFull(t, app, http.MethodPost, "/api/v1/air-rescuer-checklist/"+checklistIDStr+"/items/create", []byte(`{"data":{"type":"air_rescuer_checklist_item_create","attributes":{"items":[{"name":"ok"}]}}}`))
		if resp.StatusCode != http.StatusNotFound {
			t.Fatalf("expected 404 create items service error, got %d", resp.StatusCode)
		}

		svcGetErr := &checklistServiceFullMock{
			createChecklistItemsFn: func(_ context.Context, _ []byte, rows []airrescuechecklist.AirRescuerChecklistItem) error {
				rows[0].ID = uuidv7.MustBytes()
				return nil
			},
			getChecklistItemByIDFn: func(context.Context, []byte) (*airrescuechecklist.ChecklistItemView, error) {
				return nil, errors.New("get item failed")
			},
		}
		app = newAirRescuerChecklistFullTestApp(NewAirRescuerChecklistHandler(svcGetErr))
		resp, _ = doChecklistJSONRequestFull(t, app, http.MethodPost, "/api/v1/air-rescuer-checklist/"+checklistIDStr+"/items/create", []byte(`{"data":{"type":"air_rescuer_checklist_item_create","attributes":{"items":[{"name":"ok"}]}}}`))
		if resp.StatusCode == http.StatusCreated {
			t.Fatalf("expected failure when loading created item fails")
		}
	})

	t.Run("update item failure branches", func(t *testing.T) {
		app := newAirRescuerChecklistFullTestApp(NewAirRescuerChecklistHandler(&checklistServiceFullMock{}))
		resp, _ := doChecklistJSONRequestFull(t, app, http.MethodPatch, "/api/v1/air-rescuer-checklist/items/update/not-uuid", nil)
		if resp.StatusCode != http.StatusUnprocessableEntity {
			t.Fatalf("expected 422 invalid path item_uuid, got %d", resp.StatusCode)
		}
		resp, _ = doChecklistJSONRequestFull(t, app, http.MethodPatch, "/api/v1/air-rescuer-checklist/items/update/"+itemIDStr, []byte(`{`))
		if resp.StatusCode != http.StatusBadRequest {
			t.Fatalf("expected 400 invalid json, got %d", resp.StatusCode)
		}
		resp, _ = doChecklistJSONRequestFull(t, app, http.MethodPatch, "/api/v1/air-rescuer-checklist/items/update/"+itemIDStr, []byte(`{"data":{"type":"wrong","attributes":{}}}`))
		if resp.StatusCode != http.StatusUnprocessableEntity {
			t.Fatalf("expected 422 validator, got %d", resp.StatusCode)
		}
		resp, _ = doChecklistJSONRequestFull(t, app, http.MethodPatch, "/api/v1/air-rescuer-checklist/items/update/"+itemIDStr, []byte(`{"data":{"type":"air_rescuer_checklist_item_update","id":"bad","attributes":{"name":"x"}}}`))
		if resp.StatusCode != http.StatusUnprocessableEntity {
			t.Fatalf("expected 422 invalid body id, got %d", resp.StatusCode)
		}
		resp, _ = doChecklistJSONRequestFull(t, app, http.MethodPatch, "/api/v1/air-rescuer-checklist/items/update/"+itemIDStr, []byte(`{"data":{"type":"air_rescuer_checklist_item_update","id":"`+mustUUIDStringChecklist(t, uuidv7.MustBytes())+`","attributes":{"name":"x"}}}`))
		if resp.StatusCode != http.StatusUnprocessableEntity {
			t.Fatalf("expected 422 id mismatch, got %d", resp.StatusCode)
		}
		resp, _ = doChecklistJSONRequestFull(t, app, http.MethodPatch, "/api/v1/air-rescuer-checklist/items/update/"+itemIDStr, []byte(`{"data":{"type":"air_rescuer_checklist_item_update","attributes":{}}}`))
		if resp.StatusCode != http.StatusUnprocessableEntity {
			t.Fatalf("expected 422 empty attrs, got %d", resp.StatusCode)
		}

		svcGetErr := &checklistServiceFullMock{
			getChecklistItemByIDFn: func(context.Context, []byte) (*airrescuechecklist.ChecklistItemView, error) {
				return nil, errors.New("boom")
			},
		}
		app = newAirRescuerChecklistFullTestApp(NewAirRescuerChecklistHandler(svcGetErr))
		resp, _ = doChecklistJSONRequestFull(t, app, http.MethodPatch, "/api/v1/air-rescuer-checklist/items/update/"+itemIDStr, []byte(`{"data":{"type":"air_rescuer_checklist_item_update","attributes":{"name":"x"}}}`))
		if resp.StatusCode == http.StatusOK {
			t.Fatalf("expected non-200 when get existing fails")
		}

		svcNotFound := &checklistServiceFullMock{}
		app = newAirRescuerChecklistFullTestApp(NewAirRescuerChecklistHandler(svcNotFound))
		resp, _ = doChecklistJSONRequestFull(t, app, http.MethodPatch, "/api/v1/air-rescuer-checklist/items/update/"+itemIDStr, []byte(`{"data":{"type":"air_rescuer_checklist_item_update","attributes":{"name":"x"}}}`))
		if resp.StatusCode != http.StatusNotFound {
			t.Fatalf("expected 404 item not found, got %d", resp.StatusCode)
		}

		svcBlankName := &checklistServiceFullMock{
			getChecklistItemByIDFn: func(context.Context, []byte) (*airrescuechecklist.ChecklistItemView, error) {
				return &airrescuechecklist.ChecklistItemView{ID: itemID, Name: "Old", Position: 1}, nil
			},
		}
		app = newAirRescuerChecklistFullTestApp(NewAirRescuerChecklistHandler(svcBlankName))
		resp, _ = doChecklistJSONRequestFull(t, app, http.MethodPatch, "/api/v1/air-rescuer-checklist/items/update/"+itemIDStr, []byte(`{"data":{"type":"air_rescuer_checklist_item_update","attributes":{"name":" "}}}`))
		if resp.StatusCode != http.StatusUnprocessableEntity {
			t.Fatalf("expected 422 blank update name, got %d", resp.StatusCode)
		}

		svcUpdateErr := &checklistServiceFullMock{
			getChecklistItemByIDFn: func(context.Context, []byte) (*airrescuechecklist.ChecklistItemView, error) {
				return &airrescuechecklist.ChecklistItemView{ID: itemID, Name: "Old", Position: 1}, nil
			},
			updateChecklistItemFn: func(context.Context, *airrescuechecklist.AirRescuerChecklistItem) error {
				return gorm.ErrRecordNotFound
			},
		}
		app = newAirRescuerChecklistFullTestApp(NewAirRescuerChecklistHandler(svcUpdateErr))
		resp, _ = doChecklistJSONRequestFull(t, app, http.MethodPatch, "/api/v1/air-rescuer-checklist/items/update/"+itemIDStr, []byte(`{"data":{"type":"air_rescuer_checklist_item_update","attributes":{"name":"ok"}}}`))
		if resp.StatusCode != http.StatusNotFound {
			t.Fatalf("expected 404 update item service error, got %d", resp.StatusCode)
		}

		callCount := 0
		svcUpdatedMissing := &checklistServiceFullMock{
			getChecklistItemByIDFn: func(context.Context, []byte) (*airrescuechecklist.ChecklistItemView, error) {
				callCount++
				if callCount == 1 {
					return &airrescuechecklist.ChecklistItemView{ID: itemID, Name: "Old", Position: 1}, nil
				}
				return nil, nil
			},
		}
		app = newAirRescuerChecklistFullTestApp(NewAirRescuerChecklistHandler(svcUpdatedMissing))
		resp, _ = doChecklistJSONRequestFull(t, app, http.MethodPatch, "/api/v1/air-rescuer-checklist/items/update/"+itemIDStr, []byte(`{"data":{"type":"air_rescuer_checklist_item_update","attributes":{"name":"ok"}}}`))
		if resp.StatusCode != http.StatusNotFound {
			t.Fatalf("expected 404 when updated row missing, got %d", resp.StatusCode)
		}

		callCount = 0
		svcUpdatedGetErr := &checklistServiceFullMock{
			getChecklistItemByIDFn: func(context.Context, []byte) (*airrescuechecklist.ChecklistItemView, error) {
				callCount++
				if callCount == 1 {
					return &airrescuechecklist.ChecklistItemView{ID: itemID, Name: "Old", Position: 1}, nil
				}
				return nil, errors.New("refresh failed")
			},
		}
		app = newAirRescuerChecklistFullTestApp(NewAirRescuerChecklistHandler(svcUpdatedGetErr))
		resp, _ = doChecklistJSONRequestFull(t, app, http.MethodPatch, "/api/v1/air-rescuer-checklist/items/update/"+itemIDStr, []byte(`{"data":{"type":"air_rescuer_checklist_item_update","attributes":{"name":"ok"}}}`))
		if resp.StatusCode == http.StatusOK {
			t.Fatalf("expected failure when reloading updated item fails")
		}
	})

	t.Run("reorder item failure branches", func(t *testing.T) {
		app := newAirRescuerChecklistFullTestApp(NewAirRescuerChecklistHandler(&checklistServiceFullMock{}))
		resp, _ := doChecklistJSONRequestFull(t, app, http.MethodPatch, "/api/v1/air-rescuer-checklist/not-uuid/items/reorder", nil)
		if resp.StatusCode != http.StatusUnprocessableEntity {
			t.Fatalf("expected 422 invalid path uuid, got %d", resp.StatusCode)
		}

		resp, _ = doChecklistJSONRequestFull(t, app, http.MethodPatch, "/api/v1/air-rescuer-checklist/"+checklistIDStr+"/items/reorder", []byte(`{`))
		if resp.StatusCode != http.StatusBadRequest {
			t.Fatalf("expected 400 invalid json, got %d", resp.StatusCode)
		}

		resp, _ = doChecklistJSONRequestFull(t, app, http.MethodPatch, "/api/v1/air-rescuer-checklist/"+checklistIDStr+"/items/reorder", []byte(`{"data":{"type":"wrong","attributes":{}}}`))
		if resp.StatusCode != http.StatusUnprocessableEntity {
			t.Fatalf("expected 422 validator, got %d", resp.StatusCode)
		}

		resp, _ = doChecklistJSONRequestFull(t, app, http.MethodPatch, "/api/v1/air-rescuer-checklist/"+checklistIDStr+"/items/reorder", []byte(`{
			"data":{"type":"air_rescuer_checklist_item_reorder","attributes":{"items":[{"item_uuid":"bad-uuid","position":1}]}}
		}`))
		if resp.StatusCode != http.StatusUnprocessableEntity {
			t.Fatalf("expected 422 invalid item_uuid, got %d", resp.StatusCode)
		}

		resp, _ = doChecklistJSONRequestFull(t, app, http.MethodPatch, "/api/v1/air-rescuer-checklist/"+checklistIDStr+"/items/reorder", []byte(`{
			"data":{"type":"air_rescuer_checklist_item_reorder","attributes":{"items":[{"item_uuid":"`+itemIDStr+`","position":1},{"item_uuid":"`+itemIDStr+`","position":2}]}}
		}`))
		if resp.StatusCode != http.StatusUnprocessableEntity {
			t.Fatalf("expected 422 duplicate item_uuid, got %d", resp.StatusCode)
		}

		svcNotFound := &checklistServiceFullMock{
			reorderChecklistItemsFn: func(context.Context, []byte, []airrescuechecklist.ChecklistItemReorderInput, []byte) error {
				return gorm.ErrRecordNotFound
			},
		}
		app = newAirRescuerChecklistFullTestApp(NewAirRescuerChecklistHandler(svcNotFound))
		resp, _ = doChecklistJSONRequestFull(t, app, http.MethodPatch, "/api/v1/air-rescuer-checklist/"+checklistIDStr+"/items/reorder", []byte(`{
			"data":{"type":"air_rescuer_checklist_item_reorder","attributes":{"items":[{"item_uuid":"`+itemIDStr+`","position":1}]}}
		}`))
		if resp.StatusCode != http.StatusNotFound {
			t.Fatalf("expected 404 reorder service error, got %d", resp.StatusCode)
		}
	})

	t.Run("delete item branches", func(t *testing.T) {
		svc := &checklistServiceFullMock{
			deleteChecklistItemFn: func(context.Context, []byte, []byte) error { return gorm.ErrRecordNotFound },
		}
		app := newAirRescuerChecklistFullTestApp(NewAirRescuerChecklistHandler(svc))
		resp, _ := doChecklistJSONRequestFull(t, app, http.MethodDelete, "/api/v1/air-rescuer-checklist/items/delete/not-uuid", nil)
		if resp.StatusCode != http.StatusUnprocessableEntity {
			t.Fatalf("expected 422 invalid item uuid, got %d", resp.StatusCode)
		}
		resp, _ = doChecklistJSONRequestFull(t, app, http.MethodDelete, "/api/v1/air-rescuer-checklist/items/delete/"+itemIDStr, nil)
		if resp.StatusCode != http.StatusNotFound {
			t.Fatalf("expected 404 item delete service error, got %d", resp.StatusCode)
		}
	})

	t.Run("create parse-level validation branches", func(t *testing.T) {
		svc := &checklistServiceFullMock{
			listHEMSBasesFn: func(context.Context, airrescuechecklist.HEMSBaseFilter) ([]airrescuechecklist.HEMSBaseView, error) {
				return []airrescuechecklist.HEMSBaseView{{ID: baseID, BaseName: "Gallus 1", BaseAbbreviation: "G1"}}, nil
			},
		}
		app := newAirRescuerChecklistFullTestApp(NewAirRescuerChecklistHandler(svc))

		resp, _ := doChecklistJSONRequestFull(t, app, http.MethodPost, "/api/v1/air-rescuer-checklist/create", []byte(`{
			"data":{"type":"air_rescuer_checklist_create","attributes":{"base_id":"bad","checklists":[{"scope_code":"TA","title":"x"}]}}
		}`))
		if resp.StatusCode != http.StatusUnprocessableEntity {
			t.Fatalf("expected 422 invalid base uuid, got %d", resp.StatusCode)
		}

		resp, _ = doChecklistJSONRequestFull(t, app, http.MethodPost, "/api/v1/air-rescuer-checklist/create", []byte(`{
			"data":{"type":"air_rescuer_checklist_create","attributes":{"base_id":"`+baseIDStr+`","checklists":[]}}
		}`))
		if resp.StatusCode != http.StatusUnprocessableEntity {
			t.Fatalf("expected 422 empty checklists, got %d", resp.StatusCode)
		}

		resp, _ = doChecklistJSONRequestFull(t, app, http.MethodPost, "/api/v1/air-rescuer-checklist/create", []byte(`{
			"data":{"type":"air_rescuer_checklist_create","attributes":{"base_id":"`+baseIDStr+`","checklists":[{"scope_code":" ","title":"x"}]}}
		}`))
		if resp.StatusCode != http.StatusUnprocessableEntity {
			t.Fatalf("expected 422 blank scope, got %d", resp.StatusCode)
		}

		resp, _ = doChecklistJSONRequestFull(t, app, http.MethodPost, "/api/v1/air-rescuer-checklist/create", []byte(`{
			"data":{"type":"air_rescuer_checklist_create","attributes":{"base_id":"`+baseIDStr+`","checklists":[{"scope_code":"CAT","title":"x"}]}}
		}`))
		if resp.StatusCode != http.StatusUnprocessableEntity {
			t.Fatalf("expected 422 invalid scope, got %d", resp.StatusCode)
		}

		resp, _ = doChecklistJSONRequestFull(t, app, http.MethodPost, "/api/v1/air-rescuer-checklist/create", []byte(`{
			"data":{"type":"air_rescuer_checklist_create","attributes":{"base_id":"`+baseIDStr+`","checklists":[{"scope_code":"TA","title":" "}]}}
		}`))
		if resp.StatusCode != http.StatusUnprocessableEntity {
			t.Fatalf("expected 422 blank title, got %d", resp.StatusCode)
		}

		resp, _ = doChecklistJSONRequestFull(t, app, http.MethodPost, "/api/v1/air-rescuer-checklist/create", []byte(`{
			"data":{"type":"air_rescuer_checklist_create","attributes":{"base_id":"`+baseIDStr+`","checklists":[{"scope_code":"TA","title":"ok","items":[{"name":" "}]}]}}
		}`))
		if resp.StatusCode != http.StatusUnprocessableEntity {
			t.Fatalf("expected 422 blank item name, got %d", resp.StatusCode)
		}
	})
}

func TestAirRescuerChecklistHandlerLoadHelpersAndPosition(t *testing.T) {
	checklistID := uuidv7.MustBytes()
	baseID := uuidv7.MustBytes()
	now := time.Now().UTC()

	t.Run("load checklist resource branches", func(t *testing.T) {
		h := NewAirRescuerChecklistHandler(&checklistServiceFullMock{
			getChecklistByIDFn: func(context.Context, []byte) (*airrescuechecklist.ChecklistHeaderView, error) {
				return nil, errors.New("get failed")
			},
		})
		_, found, err := h.loadChecklistResource(context.Background(), checklistID)
		if err == nil || found {
			t.Fatalf("expected get error branch")
		}

		h = NewAirRescuerChecklistHandler(&checklistServiceFullMock{})
		_, found, err = h.loadChecklistResource(context.Background(), checklistID)
		if err != nil || found {
			t.Fatalf("expected not found branch")
		}

		h = NewAirRescuerChecklistHandler(&checklistServiceFullMock{
			getChecklistByIDFn: func(context.Context, []byte) (*airrescuechecklist.ChecklistHeaderView, error) {
				return &airrescuechecklist.ChecklistHeaderView{ID: checklistID, HEMSBaseID: baseID, ScopeCode: "TA", Title: "Daily", CreatedAt: now, UpdatedAt: now}, nil
			},
			listChecklistItemsFn: func(context.Context, [][]byte) ([]airrescuechecklist.ChecklistItemView, error) {
				return nil, errors.New("items failed")
			},
		})
		_, found, err = h.loadChecklistResource(context.Background(), checklistID)
		if err == nil || found {
			t.Fatalf("expected item list error branch")
		}
	})

	t.Run("load checklist groups branches", func(t *testing.T) {
		h := NewAirRescuerChecklistHandler(&checklistServiceFullMock{
			listHEMSBasesFn: func(context.Context, airrescuechecklist.HEMSBaseFilter) ([]airrescuechecklist.HEMSBaseView, error) {
				return nil, errors.New("base failed")
			},
		})
		_, err := h.loadChecklistGroups(context.Background(), airrescuechecklist.ChecklistHeaderFilter{}, airrescuechecklist.HEMSBaseFilter{}, "")
		if err == nil {
			t.Fatalf("expected base error")
		}

		h = NewAirRescuerChecklistHandler(&checklistServiceFullMock{
			listHEMSBasesFn: func(context.Context, airrescuechecklist.HEMSBaseFilter) ([]airrescuechecklist.HEMSBaseView, error) {
				return []airrescuechecklist.HEMSBaseView{{ID: baseID, BaseName: "Base", BaseAbbreviation: "B1"}}, nil
			},
			listChecklistHeadersFn: func(context.Context, airrescuechecklist.ChecklistHeaderFilter) ([]airrescuechecklist.ChecklistHeaderView, error) {
				return nil, errors.New("header failed")
			},
		})
		_, err = h.loadChecklistGroups(context.Background(), airrescuechecklist.ChecklistHeaderFilter{}, airrescuechecklist.HEMSBaseFilter{}, "")
		if err == nil {
			t.Fatalf("expected header error")
		}

		h = NewAirRescuerChecklistHandler(&checklistServiceFullMock{
			listHEMSBasesFn: func(context.Context, airrescuechecklist.HEMSBaseFilter) ([]airrescuechecklist.HEMSBaseView, error) {
				return []airrescuechecklist.HEMSBaseView{{ID: baseID, BaseName: "Base", BaseAbbreviation: "B1"}}, nil
			},
			listChecklistHeadersFn: func(context.Context, airrescuechecklist.ChecklistHeaderFilter) ([]airrescuechecklist.ChecklistHeaderView, error) {
				return []airrescuechecklist.ChecklistHeaderView{{ID: checklistID, HEMSBaseID: baseID, ScopeCode: "TA", Title: "Daily", Position: 1, CreatedAt: now, UpdatedAt: now}}, nil
			},
			listChecklistItemsFn: func(context.Context, [][]byte) ([]airrescuechecklist.ChecklistItemView, error) {
				return nil, errors.New("items failed")
			},
		})
		_, err = h.loadChecklistGroups(context.Background(), airrescuechecklist.ChecklistHeaderFilter{}, airrescuechecklist.HEMSBaseFilter{}, "")
		if err == nil {
			t.Fatalf("expected item list error")
		}
	})

	if checklistPositionOrDefault(nil) != 1 {
		t.Fatalf("nil position should default to 1")
	}
	zero := 0
	if checklistPositionOrDefault(&zero) != 1 {
		t.Fatalf("zero position should default to 1")
	}
	two := 2
	if checklistPositionOrDefault(&two) != 2 {
		t.Fatalf("positive position should be preserved")
	}
}
