package molecules

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

	"github.com/steveyegge/beads/internal/storage/sqlite"
	"github.com/steveyegge/beads/internal/types"
)

func TestLoadMoleculesFromFile(t *testing.T) {
	// Create a temporary directory
	tempDir := t.TempDir()

	// Create a test molecules.jsonl file
	moleculesPath := filepath.Join(tempDir, "molecules.jsonl")
	content := `{"id":"mol-test-1","title":"Test Molecule 1","issue_type":"molecule","status":"open"}
{"id":"mol-test-2","title":"Test Molecule 2","issue_type":"molecule","status":"open"}`
	if err := os.WriteFile(moleculesPath, []byte(content), 0600); err != nil {
		t.Fatalf("Failed to write test file: %v", err)
	}

	// Load molecules
	molecules, err := loadMoleculesFromFile(moleculesPath)
	if err != nil {
		t.Fatalf("Failed to load molecules: %v", err)
	}

	if len(molecules) != 2 {
		t.Errorf("Expected 2 molecules, got %d", len(molecules))
	}

	// Check that IsTemplate is set
	for _, mol := range molecules {
		if !mol.IsTemplate {
			t.Errorf("Molecule %s should have IsTemplate=true", mol.ID)
		}
	}

	// Check specific fields
	if molecules[0].ID != "mol-test-1" {
		t.Errorf("Expected ID 'mol-test-1', got '%s'", molecules[0].ID)
	}
	if molecules[0].Title != "Test Molecule 1" {
		t.Errorf("Expected Title 'Test Molecule 1', got '%s'", molecules[0].Title)
	}
}

func TestLoadMoleculesFromNonexistentFile(t *testing.T) {
	molecules, err := loadMoleculesFromFile("/nonexistent/path/molecules.jsonl")
	if err != nil {
		t.Errorf("Expected nil error for nonexistent file, got: %v", err)
	}
	if molecules != nil {
		t.Errorf("Expected nil molecules for nonexistent file, got: %v", molecules)
	}
}

func TestLoader_LoadAll(t *testing.T) {
	ctx := context.Background()

	// Create temporary directories
	tempDir := t.TempDir()
	beadsDir := filepath.Join(tempDir, ".beads")
	if err := os.MkdirAll(beadsDir, 0750); err != nil {
		t.Fatalf("Failed to create beads dir: %v", err)
	}

	// Create a test database
	dbPath := filepath.Join(beadsDir, "test.db")
	store, err := sqlite.New(ctx, dbPath)
	if err != nil {
		t.Fatalf("Failed to create store: %v", err)
	}
	defer store.Close()

	// Set issue prefix (required by storage)
	if err := store.SetConfig(ctx, "issue_prefix", "test"); err != nil {
		t.Fatalf("Failed to set prefix: %v", err)
	}

	// Create a project-level molecules.jsonl
	moleculesPath := filepath.Join(beadsDir, "molecules.jsonl")
	content := `{"id":"mol-feature","title":"Feature Template","issue_type":"molecule","status":"open","description":"Standard feature workflow"}
{"id":"mol-bugfix","title":"Bugfix Template","issue_type":"molecule","status":"open","description":"Bug fix workflow"}`
	if err := os.WriteFile(moleculesPath, []byte(content), 0600); err != nil {
		t.Fatalf("Failed to write molecules file: %v", err)
	}

	// Load molecules
	loader := NewLoader(store)
	result, err := loader.LoadAll(ctx, beadsDir)
	if err != nil {
		t.Fatalf("LoadAll failed: %v", err)
	}

	if result.Loaded != 2 {
		t.Errorf("Expected 2 loaded molecules, got %d", result.Loaded)
	}

	// Verify molecules are in the database
	mol1, err := store.GetIssue(ctx, "mol-feature")
	if err != nil {
		t.Fatalf("Failed to get mol-feature: %v", err)
	}
	if mol1 == nil {
		t.Fatal("mol-feature not found in database")
	}
	if !mol1.IsTemplate {
		t.Error("mol-feature should be marked as template")
	}
	if mol1.Title != "Feature Template" {
		t.Errorf("Expected title 'Feature Template', got '%s'", mol1.Title)
	}

	mol2, err := store.GetIssue(ctx, "mol-bugfix")
	if err != nil {
		t.Fatalf("Failed to get mol-bugfix: %v", err)
	}
	if mol2 == nil {
		t.Fatal("mol-bugfix not found in database")
	}
	if !mol2.IsTemplate {
		t.Error("mol-bugfix should be marked as template")
	}
}

func TestLoader_SkipExistingMolecules(t *testing.T) {
	ctx := context.Background()

	// Create temporary directories
	tempDir := t.TempDir()
	beadsDir := filepath.Join(tempDir, ".beads")
	if err := os.MkdirAll(beadsDir, 0750); err != nil {
		t.Fatalf("Failed to create beads dir: %v", err)
	}

	// Create a test database
	dbPath := filepath.Join(beadsDir, "test.db")
	store, err := sqlite.New(ctx, dbPath)
	if err != nil {
		t.Fatalf("Failed to create store: %v", err)
	}
	defer store.Close()

	// Set issue prefix
	if err := store.SetConfig(ctx, "issue_prefix", "test"); err != nil {
		t.Fatalf("Failed to set prefix: %v", err)
	}

	// Pre-create a molecule in the database (skip prefix validation for mol-* IDs)
	existingMol := &types.Issue{
		ID:         "mol-existing",
		Title:      "Existing Molecule",
		IssueType:  types.TypeMolecule,
		Status:     types.StatusOpen,
		IsTemplate: true,
	}
	opts := sqlite.BatchCreateOptions{SkipPrefixValidation: true}
	if err := store.CreateIssuesWithFullOptions(ctx, []*types.Issue{existingMol}, "test", opts); err != nil {
		t.Fatalf("Failed to create existing molecule: %v", err)
	}

	// Create a molecules.jsonl with the same ID
	moleculesPath := filepath.Join(beadsDir, "molecules.jsonl")
	content := `{"id":"mol-existing","title":"Updated Molecule","issue_type":"molecule","status":"open"}
{"id":"mol-new","title":"New Molecule","issue_type":"molecule","status":"open"}`
	if err := os.WriteFile(moleculesPath, []byte(content), 0600); err != nil {
		t.Fatalf("Failed to write molecules file: %v", err)
	}

	// Load molecules
	loader := NewLoader(store)
	result, err := loader.LoadAll(ctx, beadsDir)
	if err != nil {
		t.Fatalf("LoadAll failed: %v", err)
	}

	// Should only load the new one (existing one is skipped)
	if result.Loaded != 1 {
		t.Errorf("Expected 1 loaded molecule, got %d", result.Loaded)
	}

	// Verify the existing molecule wasn't updated
	mol, err := store.GetIssue(ctx, "mol-existing")
	if err != nil {
		t.Fatalf("Failed to get mol-existing: %v", err)
	}
	if mol.Title != "Existing Molecule" {
		t.Errorf("Expected title 'Existing Molecule' (unchanged), got '%s'", mol.Title)
	}
}

func TestGetBuiltinMolecules(t *testing.T) {
	molecules := getBuiltinMolecules()
	// For now, we expect no built-in molecules (can be added later)
	if molecules == nil {
		// This is expected for now
		return
	}
	// When built-in molecules are added, verify they all have IsTemplate=true
	for _, mol := range molecules {
		if !mol.IsTemplate {
			t.Errorf("Built-in molecule %s should have IsTemplate=true", mol.ID)
		}
	}
}
