package service

import (
	"os"
	"path/filepath"
	"testing"

	"3588AdminBackend/internal/models"
	"3588AdminBackend/internal/storage"
)

func TestSyncStandardModelsFromDirectory(t *testing.T) {
	dir := t.TempDir()
	path := filepath.Join(dir, "face_det_scrfd_500m_640_rk3588.rknn")
	if err := os.WriteFile(path, []byte("model-bytes"), 0o644); err != nil {
		t.Fatalf("WriteFile: %v", err)
	}

	store, err := storage.OpenSQLite(filepath.Join(t.TempDir(), "app.db"))
	if err != nil {
		t.Fatalf("OpenSQLite: %v", err)
	}
	defer store.Close()

	modelsRepo := storage.NewModelsRepo(store.DB())
	svc := NewModelManagementService(modelsRepo)

	if err := svc.SyncStandardModelsFromDirectory(dir); err != nil {
		t.Fatalf("SyncStandardModelsFromDirectory: %v", err)
	}

	items, err := modelsRepo.List()
	if err != nil {
		t.Fatalf("List: %v", err)
	}
	if len(items) != 1 || items[0].FileName != "face_det_scrfd_500m_640_rk3588.rknn" {
		t.Fatalf("unexpected synced models: %#v", items)
	}
	if items[0].SHA256 == "" {
		t.Fatalf("expected sha256 to be populated: %#v", items[0])
	}
	if items[0].ModelType != "face_detection" {
		t.Fatalf("expected inferred model type face_detection, got %#v", items[0])
	}
}

func TestBuildModelStatusBoardMarksMissingAndMismatch(t *testing.T) {
	modelsList := []storage.StandardModelRecord{
		{Name: "face_det", FileName: "face_det.rknn", SHA256: "sha-1"},
		{Name: "face_recog", FileName: "face_recog.rknn", SHA256: "sha-2"},
	}
	devices := []*models.Device{
		{DeviceID: "edge-01", DeviceName: "设备一", Online: true},
	}
	installed := map[string][]InstalledModelStatus{
		"edge-01": {
			{Name: "face_det", FileName: "face_det.rknn", SHA256: "sha-1"},
		},
	}

	board := BuildModelStatusBoard(modelsList, devices, installed)

	if board.Summary.MissingDevices != 1 {
		t.Fatalf("expected one device with missing models, got %#v", board.Summary)
	}
	if len(board.Rows) != 1 || len(board.Rows[0].Cells) != 2 {
		t.Fatalf("unexpected board rows: %#v", board.Rows)
	}
	if board.Rows[0].Cells[1].Status != "missing" {
		t.Fatalf("expected second model to be missing, got %#v", board.Rows[0].Cells[1])
	}
}

func TestBuildModelStatusBoardSeparatesExtraModels(t *testing.T) {
	modelsList := []storage.StandardModelRecord{
		{Name: "face_det", FileName: "face_det.rknn", SHA256: "sha-1"},
	}
	devices := []*models.Device{
		{DeviceID: "edge-01", DeviceName: "设备一", Online: true},
	}
	installed := map[string][]InstalledModelStatus{
		"edge-01": {
			{Name: "face_det", FileName: "face_det.rknn", SHA256: "sha-1"},
			{Name: "best-640", FileName: "best-640.rknn", SHA256: "sha-x"},
			{Name: "mobilefacenet_arcface", FileName: "mobilefacenet_arcface.rknn", SHA256: "sha-y"},
		},
	}

	board := BuildModelStatusBoard(modelsList, devices, installed)

	if len(board.Rows) != 1 {
		t.Fatalf("unexpected board rows: %#v", board.Rows)
	}
	if got := board.Rows[0].ExtraModelCount; got != 2 {
		t.Fatalf("expected 2 extra models, got %#v", board.Rows[0])
	}
	if len(board.Rows[0].ExtraModels) != 2 {
		t.Fatalf("expected extra model details to be preserved, got %#v", board.Rows[0].ExtraModels)
	}
	if board.Rows[0].ExtraModels[0].Name != "best-640" || board.Rows[0].ExtraModels[1].Name != "mobilefacenet_arcface" {
		t.Fatalf("expected sorted extra models, got %#v", board.Rows[0].ExtraModels)
	}
}
