package browser

import (
	"encoding/json"
	"os"
	"path/filepath"
	"testing"
)

// writePreferences writes a synthetic Preferences JSON file into profileDir.
func writePreferences(t *testing.T, profileDir string, settings map[string]any) {
	t.Helper()
	prefs := map[string]any{
		"extensions": map[string]any{
			"settings": settings,
		},
	}
	data, err := json.Marshal(prefs)
	if err != nil {
		t.Fatalf("json.Marshal Preferences: %v", err)
	}
	if err := os.WriteFile(filepath.Join(profileDir, "Preferences"), data, 0o600); err != nil {
		t.Fatalf("WriteFile Preferences: %v", err)
	}
}

func TestListChromeProfileExtensions(t *testing.T) {
	t.Run("dos extensiones con IDs ordenados y campos correctos", func(t *testing.T) {
		tmpDir := t.TempDir()
		profilePath := filepath.Join(tmpDir, "Default")
		os.MkdirAll(profilePath, 0o755)

		settings := map[string]any{
			// location 7 = external_policy_download, state 1 = enabled
			"dddbmnkl": map[string]any{
				"manifest": map[string]any{
					"name":    "uBlock Origin Lite",
					"version": "1.0.2",
				},
				"location": 7,
				"state":    1,
			},
			// location 4 = unpacked, state 1 = enabled
			"aaabcdef": map[string]any{
				"manifest": map[string]any{
					"name":    "My Dev Extension",
					"version": "0.1.0",
				},
				"location": 4,
				"state":    1,
			},
		}
		writePreferences(t, profilePath, settings)

		exts, err := ListChromeProfileExtensions(tmpDir, "Default")
		if err != nil {
			t.Fatalf("error inesperado: %v", err)
		}
		if len(exts) != 2 {
			t.Fatalf("esperaba 2 extensiones, got %d", len(exts))
		}

		// Sorted by ID: "aaabcdef" < "dddbmnkl"
		if exts[0].ID != "aaabcdef" {
			t.Errorf("exts[0].ID = %q, want %q", exts[0].ID, "aaabcdef")
		}
		if exts[1].ID != "dddbmnkl" {
			t.Errorf("exts[1].ID = %q, want %q", exts[1].ID, "dddbmnkl")
		}

		// Check names and versions
		if exts[0].Name != "My Dev Extension" {
			t.Errorf("exts[0].Name = %q, want %q", exts[0].Name, "My Dev Extension")
		}
		if exts[1].Name != "uBlock Origin Lite" {
			t.Errorf("exts[1].Name = %q, want %q", exts[1].Name, "uBlock Origin Lite")
		}
		if exts[0].Version != "0.1.0" {
			t.Errorf("exts[0].Version = %q, want %q", exts[0].Version, "0.1.0")
		}
		if exts[1].Version != "1.0.2" {
			t.Errorf("exts[1].Version = %q, want %q", exts[1].Version, "1.0.2")
		}

		// FromPolicy: location 7 → true; location 4 → false
		if exts[0].FromPolicy {
			t.Errorf("exts[0] (unpacked): FromPolicy debe ser false")
		}
		if !exts[1].FromPolicy {
			t.Errorf("exts[1] (external_policy_download): FromPolicy debe ser true")
		}

		// Location strings
		if exts[0].Location != "unpacked" {
			t.Errorf("exts[0].Location = %q, want %q", exts[0].Location, "unpacked")
		}
		if exts[1].Location != "external_policy_download" {
			t.Errorf("exts[1].Location = %q, want %q", exts[1].Location, "external_policy_download")
		}

		// Both enabled
		if !exts[0].Enabled {
			t.Error("exts[0]: Enabled debe ser true")
		}
		if !exts[1].Enabled {
			t.Error("exts[1]: Enabled debe ser true")
		}
	})

	t.Run("extension con state 0 tiene Enabled false", func(t *testing.T) {
		tmpDir := t.TempDir()
		profilePath := filepath.Join(tmpDir, "Default")
		os.MkdirAll(profilePath, 0o755)

		settings := map[string]any{
			"extdisabled": map[string]any{
				"manifest": map[string]any{
					"name":    "Disabled Ext",
					"version": "2.0.0",
				},
				"location": 1,
				"state":    0,
			},
		}
		writePreferences(t, profilePath, settings)

		exts, err := ListChromeProfileExtensions(tmpDir, "Default")
		if err != nil {
			t.Fatalf("error inesperado: %v", err)
		}
		if len(exts) != 1 {
			t.Fatalf("esperaba 1 extensión, got %d", len(exts))
		}
		if exts[0].Enabled {
			t.Error("Enabled debe ser false cuando state=0")
		}
	})

	t.Run("perfil sin Preferences devuelve error", func(t *testing.T) {
		tmpDir := t.TempDir()
		os.MkdirAll(filepath.Join(tmpDir, "Default"), 0o755)
		// No Preferences file created.

		_, err := ListChromeProfileExtensions(tmpDir, "Default")
		if err == nil {
			t.Error("esperaba error al faltar Preferences, got nil")
		}
	})

	t.Run("Preferences sin extensions.settings devuelve slice vacío sin error", func(t *testing.T) {
		tmpDir := t.TempDir()
		profilePath := filepath.Join(tmpDir, "Default")
		os.MkdirAll(profilePath, 0o755)

		// Write a Preferences with no extensions key at all.
		if err := os.WriteFile(filepath.Join(profilePath, "Preferences"), []byte(`{}`), 0o600); err != nil {
			t.Fatal(err)
		}

		exts, err := ListChromeProfileExtensions(tmpDir, "Default")
		if err != nil {
			t.Fatalf("error inesperado: %v", err)
		}
		if len(exts) != 0 {
			t.Errorf("esperaba slice vacío, got %d elementos", len(exts))
		}
	})

	t.Run("fallback a Extensions/<id>/<ver>/manifest.json cuando falta manifest en Preferences", func(t *testing.T) {
		tmpDir := t.TempDir()
		profilePath := filepath.Join(tmpDir, "Default")
		os.MkdirAll(profilePath, 0o755)

		const extID = "fallbackext"
		const extVer = "3.1.0"

		// Preferences entry without a manifest field.
		settings := map[string]any{
			extID: map[string]any{
				"location": 4,
				"state":    1,
				// no "manifest" key
			},
		}
		writePreferences(t, profilePath, settings)

		// Create the on-disk manifest.json.
		manifestDir := filepath.Join(profilePath, "Extensions", extID, extVer)
		os.MkdirAll(manifestDir, 0o755)
		manifestData, _ := json.Marshal(map[string]any{
			"name":    "Fallback Extension",
			"version": extVer,
		})
		os.WriteFile(filepath.Join(manifestDir, "manifest.json"), manifestData, 0o600)

		exts, err := ListChromeProfileExtensions(tmpDir, "Default")
		if err != nil {
			t.Fatalf("error inesperado: %v", err)
		}
		if len(exts) != 1 {
			t.Fatalf("esperaba 1 extensión, got %d", len(exts))
		}
		if exts[0].Name != "Fallback Extension" {
			t.Errorf("Name = %q, want %q", exts[0].Name, "Fallback Extension")
		}
		if exts[0].Version != extVer {
			t.Errorf("Version = %q, want %q", exts[0].Version, extVer)
		}
	})

	t.Run("location 5 y 10 también son FromPolicy true", func(t *testing.T) {
		tmpDir := t.TempDir()
		profilePath := filepath.Join(tmpDir, "Default")
		os.MkdirAll(profilePath, 0o755)

		settings := map[string]any{
			"comp0000": map[string]any{
				"manifest": map[string]any{"name": "Component Ext", "version": "1.0"},
				"location": 5,
				"state":    1,
			},
			"poli0000": map[string]any{
				"manifest": map[string]any{"name": "Policy Ext", "version": "1.0"},
				"location": 10,
				"state":    1,
			},
		}
		writePreferences(t, profilePath, settings)

		exts, err := ListChromeProfileExtensions(tmpDir, "Default")
		if err != nil {
			t.Fatalf("error inesperado: %v", err)
		}
		for _, ext := range exts {
			if !ext.FromPolicy {
				t.Errorf("extensión %q (location component/policy) debe tener FromPolicy=true", ext.ID)
			}
		}
	})

	t.Run("Preferences con JSON inválido devuelve error", func(t *testing.T) {
		tmpDir := t.TempDir()
		profilePath := filepath.Join(tmpDir, "Default")
		os.MkdirAll(profilePath, 0o755)
		os.WriteFile(filepath.Join(profilePath, "Preferences"), []byte(`{invalid json`), 0o600)

		_, err := ListChromeProfileExtensions(tmpDir, "Default")
		if err == nil {
			t.Error("esperaba error con JSON inválido, got nil")
		}
	})
}
