package service

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"
	helicopterusage "wucher/internal/domain/helicopter_usage"
	"wucher/internal/repository/mysql"
)

// TestFleetStatusUpdateAcceptsNegativeSummaryAndBareSchedule guards the full service path
// behind PATCH /fleet-status/update/{id}: negative summary values + an A/F schedule with
// empty type/due/ext must persist (incl. syncAutomaticAOG, which the repo-level test skips).
func TestFleetStatusUpdateAcceptsNegativeSummaryAndBareSchedule(t *testing.T) {
	dsn := fmt.Sprintf("file:fleet_update_repro_%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{},
		&helicopterusage.HelicopterUsage{},
	); err != nil {
		t.Fatalf("migrate: %v", err)
	}
	ctx := context.Background()

	heliRepo := mysql.NewHelicopterRepository(db)
	heli := &helicopter.Helicopter{Designation: "H1", Identifier: "PK-H1", Type: "Twin", NR1: true, NR2: true}
	if err := heliRepo.Create(ctx, heli); err != nil {
		t.Fatalf("create heli: %v", err)
	}
	fsRepo := mysql.NewFleetStatusRepository(db)
	fs := &fleetstatus.FleetStatus{HelicopterID: heli.ID, Status: fleetstatus.StatusActive}
	if err := fsRepo.Create(ctx, fs); err != nil {
		t.Fatalf("create fs: %v", err)
	}

	usageSvc := NewHelicopterUsageService(mysql.NewHelicopterUsageRepository(db))
	svc := NewFleetStatusService(fsRepo, nil, NewHelicopterService(heliRepo), nil).WithUsage(usageSvc)

	// Handler builds this row from the patch: full-replace schedules with one A/F entry.
	fs.MaintenanceSchedules = []fleetstatus.MaintenanceSchedule{
		{FleetStatusID: fs.ID, InspectionType: "A/F", Type: "", Due: "", Ext: ""},
	}
	fs.UpdatedBy = heli.ID // any actor
	if err := svc.Update(ctx, fs); err != nil {
		t.Fatalf("REPRO: FleetStatusService.Update FAILED: %v", err)
	}
	t.Log("FleetStatusService.Update OK (incl syncAutomaticAOG)")

	f := func(v float64) *float64 { return &v }
	if err := svc.ReviseSummary(ctx, heli.ID, helicopterusage.ManualSummaryInput{
		AirframeHours: f(1234), AirframeCycles: f(-1),
		Engine1Hours: f(1234), Engine1GpcNgN1: f(23.23), Engine1PtcNfN2: f(23.59), Engine1Ccc: f(-8),
		Engine2Hours: f(234), Engine2GpcNgN1: f(123), Engine2PtcNfN2: f(1230), Engine2Ccc: f(123),
		Landing: f(1), FlightReport: f(1), HookRelease: f(1), RotorBrakeCycle: f(1),
	}, heli.ID); err != nil {
		t.Fatalf("REPRO: ReviseSummary FAILED: %v", err)
	}
	got, _ := usageSvc.GetByHelicopterID(ctx, heli.ID)
	t.Logf("ReviseSummary OK: cycles=%v ccc1=%v ccc2=%v", got.TotalAirframeCycles, got.TotalEngine1Ccc, got.TotalEngine2Ccc)

	// The fleet GET reads the summary via GetSummaryByHelicopterID — verify it reflects the patch.
	summary, err := svc.GetSummaryByHelicopterID(ctx, heli.ID)
	if err != nil {
		t.Fatalf("GetSummaryByHelicopterID: %v", err)
	}
	if summary.Airframe.Hours == nil || *summary.Airframe.Hours != 1234 {
		t.Fatalf("summary airframe hours = %v, want 1234 (patch not reflected)", summary.Airframe.Hours)
	}
	if summary.Engine1.Hours == nil || *summary.Engine1.Hours != 1234 {
		t.Fatalf("summary engine1 hours = %v, want 1234", summary.Engine1.Hours)
	}

	// Second PATCH with a NEW value — the "ga terganti" (value doesn't change) scenario.
	if err := svc.ReviseSummary(ctx, heli.ID, helicopterusage.ManualSummaryInput{AirframeHours: f(9999)}, heli.ID); err != nil {
		t.Fatalf("second ReviseSummary: %v", err)
	}
	summary2, _ := svc.GetSummaryByHelicopterID(ctx, heli.ID)
	if summary2.Airframe.Hours == nil || *summary2.Airframe.Hours != 9999 {
		t.Fatalf("second patch: airframe hours = %v, want 9999 (VALUE DID NOT CHANGE)", summary2.Airframe.Hours)
	}
	t.Logf("both patches reflected in GET summary: first af.hours=1234, second=%v", *summary2.Airframe.Hours)
}
