package mysql

import (
	"context"
	"fmt"
	"testing"
	"time"

	"gorm.io/driver/sqlite"
	"gorm.io/gorm"

	filemanager "wucher/internal/domain/file_manager"
	fleetstatus "wucher/internal/domain/fleet_status"
	"wucher/internal/domain/helicopter"
)

func openFleetStatusTestDB(t *testing.T) *gorm.DB {
	t.Helper()
	dsn := fmt.Sprintf("file:fleet_status_test_%d?mode=memory&cache=shared", time.Now().UnixNano())
	db, err := gorm.Open(sqlite.Open(dsn), &gorm.Config{
		NowFunc: func() time.Time { return time.Now().UTC() },
	})
	if err != nil {
		t.Fatalf("open sqlite: %v", err)
	}
	if err := db.AutoMigrate(
		&filemanager.Folder{}, &filemanager.File{}, &filemanager.Attachment{},
		&helicopter.Helicopter{},
		&fleetstatus.FleetStatus{}, &fleetstatus.MaintenanceSchedule{}, &fleetstatus.FleetStatusFile{},
	); err != nil {
		t.Fatalf("auto migrate: %v", err)
	}
	return db
}

func TestFleetStatusRepositoryLatestByHelicopterIDs(t *testing.T) {
	db := openFleetStatusTestDB(t)
	repo := NewFleetStatusRepository(db)
	ctx := context.Background()

	heliRepo := NewHelicopterRepository(db)
	h1 := &helicopter.Helicopter{Designation: "H1", Identifier: "PK-H1", Type: "Twin"}
	h2 := &helicopter.Helicopter{Designation: "H2", Identifier: "PK-H2", Type: "Twin"}
	h3 := &helicopter.Helicopter{Designation: "H3", Identifier: "PK-H3", Type: "Twin"} // no fleet status
	for _, h := range []*helicopter.Helicopter{h1, h2, h3} {
		if err := heliRepo.Create(ctx, h); err != nil {
			t.Fatalf("create helicopter: %v", err)
		}
	}

	// h1: older then newer (newer = created last = latest). Plus a deleted row
	// created last, which must be ignored.
	if err := repo.Create(ctx, &fleetstatus.FleetStatus{HelicopterID: h1.ID, Status: fleetstatus.StatusActive}); err != nil {
		t.Fatalf("create fs1a: %v", err)
	}
	fs1bNewer := &fleetstatus.FleetStatus{HelicopterID: h1.ID, Status: fleetstatus.StatusServiced}
	if err := repo.Create(ctx, fs1bNewer); err != nil {
		t.Fatalf("create fs1b: %v", err)
	}
	deleted := &fleetstatus.FleetStatus{HelicopterID: h1.ID, Status: fleetstatus.StatusActive}
	if err := repo.Create(ctx, deleted); err != nil {
		t.Fatalf("create deleted: %v", err)
	}
	if err := repo.Delete(ctx, deleted.ID, nil); err != nil {
		t.Fatalf("delete fs: %v", err)
	}

	// h2: single record.
	fs2 := &fleetstatus.FleetStatus{HelicopterID: h2.ID, Status: fleetstatus.StatusActive}
	if err := repo.Create(ctx, fs2); err != nil {
		t.Fatalf("create fs2: %v", err)
	}

	out, err := repo.LatestByHelicopterIDs(ctx, [][]byte{h1.ID, h2.ID, h3.ID})
	if err != nil {
		t.Fatalf("LatestByHelicopterIDs: %v", err)
	}

	if got := out[string(h1.ID)]; got == nil || string(got.ID) != string(fs1bNewer.ID) {
		t.Fatalf("h1 latest mismatch: got %+v, want fs1b (status served, not deleted)", got)
	}
	if got := out[string(h1.ID)]; got != nil && got.Status != fleetstatus.StatusServiced {
		t.Fatalf("h1 latest should be the serviced row, got status %q", got.Status)
	}
	if got := out[string(h2.ID)]; got == nil || string(got.ID) != string(fs2.ID) {
		t.Fatalf("h2 latest mismatch: got %+v", got)
	}
	if _, ok := out[string(h3.ID)]; ok {
		t.Fatalf("h3 has no fleet status and must be absent from the map")
	}
}
