package mysql

import (
	"fmt"
	"testing"
	"time"

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

	flightdata "wucher/internal/domain/flight_data"
	"wucher/internal/shared/pkg/uuidv7"
)

func openFlightDataTestDB(t *testing.T) *gorm.DB {
	t.Helper()
	dsn := fmt.Sprintf("file:flight_data_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)
	}
	return db
}

func TestFlightDataPersistenceValues_AllowsNullableLocationFields(t *testing.T) {
	row := &flightdata.FlightData{
		ID:                   uuidv7.MustBytes(),
		MissionID:            uuidv7.MustBytes(),
		CoPilotID:            uuidv7.MustBytes(),
		FromHospitalID:       uuidv7.MustBytes(),
		ToICAOID:             uuidv7.MustBytes(),
		CreatedAt:            time.Now().UTC(),
		UpdatedAt:            time.Now().UTC(),
		CreatedBy:            uuidv7.MustBytes(),
		UpdatedBy:            uuidv7.MustBytes(),
		Status:               flightdata.StatusInProgress,
		FlightTakeOff:        time.Now().UTC(),
		FlightLanding:        time.Now().UTC(),
		FlightDuration:       4 * time.Second,
		FlightRED:            10 * time.Second,
		FlightPlanTime:       10 * time.Second,
		FlightPlanDistance:   10,
		FlightPlanTrueCourse: 10,
		FuelBeforeFlight:     10,
		FuelUpload:           10,
		FuelAfterFlight:      10,
		FuelPlanning:         10,
	}

	values := flightDataPersistenceValues(row)
	if values["from_icao_id"] != nil {
		t.Fatalf("expected from_icao_id to be nil, got %#v", values["from_icao_id"])
	}
	if values["to_hospital_id"] != nil {
		t.Fatalf("expected to_hospital_id to be nil, got %#v", values["to_hospital_id"])
	}
	if values["from_hospital_id"] == nil {
		t.Fatal("expected from_hospital_id to be populated")
	}
	if values["to_icao_id"] == nil {
		t.Fatal("expected to_icao_id to be populated")
	}
	if values["status"] != flightdata.StatusInProgress {
		t.Fatalf("expected status to be on_progress, got %#v", values["status"])
	}
}

func TestFlightDataPersistenceValues_ZeroTimesBecomeNull(t *testing.T) {
	row := &flightdata.FlightData{
		ID:        uuidv7.MustBytes(),
		MissionID: uuidv7.MustBytes(),
		CoPilotID: uuidv7.MustBytes(),
		CreatedAt: time.Now().UTC(),
		UpdatedAt: time.Now().UTC(),
		CreatedBy: uuidv7.MustBytes(),
		UpdatedBy: uuidv7.MustBytes(),
	}

	values := flightDataPersistenceValues(row)
	if values["take_off"] != nil {
		t.Fatalf("expected take_off to be nil, got %#v", values["take_off"])
	}
	if values["landing"] != nil {
		t.Fatalf("expected landing to be nil, got %#v", values["landing"])
	}
}

func TestNewFlightDataRepositoryCachesOptionalTables(t *testing.T) {
	db := openFlightDataTestDB(t)
	for _, stmt := range []string{
		`CREATE TABLE heslo_flights (id BLOB PRIMARY KEY, flight_data_id BLOB, created_at DATETIME)`,
		`CREATE TABLE heslo_slings (id BLOB PRIMARY KEY, heslo_flight_id BLOB, created_at DATETIME)`,
		`CREATE TABLE logging_slings (id BLOB PRIMARY KEY, flight_data_id BLOB, created_at DATETIME)`,
		`CREATE TABLE hec_flights (id BLOB PRIMARY KEY, flight_data_id BLOB, created_at DATETIME)`,
		`CREATE TABLE hec_slings (id BLOB PRIMARY KEY, flight_data_id BLOB, created_at DATETIME)`,
		`CREATE TABLE hec_loads (id BLOB PRIMARY KEY, flight_data_id BLOB, created_at DATETIME)`,
	} {
		if err := db.Exec(stmt).Error; err != nil {
			t.Fatalf("create table: %v", err)
		}
	}

	repo := NewFlightDataRepository(db)
	if !repo.hasHesloFlightsTable || !repo.hasHesloSlingsTable || !repo.hasLoggingSlingsTable ||
		!repo.hasHecFlightsTable || !repo.hasHecSlingsTable || !repo.hasHecLoadsTable {
		t.Fatalf("expected all optional table flags to be cached as true")
	}
}
