package topdata

import (
	"os"
	"path/filepath"
	"strings"
)

func importLegacyVFXPersistent(referenceBuilderDir, dataDir string, legacyTLK *legacyTLKData) (int, error) {
	_ = legacyTLK
	if strings.TrimSpace(referenceBuilderDir) == "" {
		return 0, nil
	}

	legacyDir := filepath.Join(referenceBuilderDir, "data", "vfx_persistent")
	if _, err := os.Stat(legacyDir); err != nil {
		if os.IsNotExist(err) {
			return 0, nil
		}
		return 0, err
	}

	targetDir := filepath.Join(dataDir, "vfx_persistent")
	targetBasePath := filepath.Join(targetDir, "base.json")
	targetLockPath := filepath.Join(targetDir, "lock.json")
	targetModulesDir := filepath.Join(targetDir, "modules")
	targetModulePath := filepath.Join(targetModulesDir, "freeformaoes.json")
	if fileExists(targetBasePath) && fileExists(targetLockPath) && fileExists(targetModulePath) {
		baseObj, baseErr := loadJSONObject(targetBasePath)
		lockObj, lockErr := loadJSONObject(targetLockPath)
		if baseErr == nil && lockErr == nil && vfxPersistentImportComplete(baseObj, lockObj) {
			legacyModulePaths, err := collectJSONRelativePaths(filepath.Join(legacyDir, "modules"))
			if err == nil {
				targetModulePaths, err := collectJSONRelativePaths(targetModulesDir)
				if err == nil && equalStringSlices(legacyModulePaths, targetModulePaths) {
					return 0, nil
				}
			}
		}
	}

	baseObj, err := loadJSONObject(filepath.Join(legacyDir, "base.json"))
	if err != nil {
		return 0, err
	}
	lockObj, err := synthesizeVFXPersistentKeys(baseObj)
	if err != nil {
		return 0, err
	}
	legacyLockObj, err := loadJSONObject(filepath.Join(legacyDir, "lock.json"))
	if err != nil {
		return 0, err
	}
	for key, value := range legacyLockObj {
		lockObj[key] = value
	}
	if err := os.MkdirAll(targetModulesDir, 0o755); err != nil {
		return 0, err
	}

	updated := 0
	for _, write := range []struct {
		path string
		obj  map[string]any
	}{
		{path: targetBasePath, obj: baseObj},
		{path: targetLockPath, obj: lockObj},
	} {
		changed, err := writeJSONObjectIfChanged(write.path, write.obj)
		if err != nil {
			return 0, err
		}
		if changed {
			updated++
		}
	}

	moduleRelPaths, err := collectJSONRelativePaths(filepath.Join(legacyDir, "modules"))
	if err != nil {
		return 0, err
	}
	for _, relPath := range moduleRelPaths {
		moduleObj, err := loadJSONObject(filepath.Join(legacyDir, "modules", filepath.FromSlash(relPath)))
		if err != nil {
			return 0, err
		}
		targetPath := filepath.Join(targetModulesDir, filepath.FromSlash(relPath))
		if err := os.MkdirAll(filepath.Dir(targetPath), 0o755); err != nil {
			return 0, err
		}
		changed, err := writeJSONObjectIfChanged(targetPath, moduleObj)
		if err != nil {
			return 0, err
		}
		if changed {
			updated++
		}
	}

	targetModulePaths, err := collectJSONRelativePaths(targetModulesDir)
	if err != nil {
		return 0, err
	}
	legacyModules := make(map[string]struct{}, len(moduleRelPaths))
	for _, relPath := range moduleRelPaths {
		legacyModules[relPath] = struct{}{}
	}
	for _, relPath := range targetModulePaths {
		if _, ok := legacyModules[relPath]; ok {
			continue
		}
		if err := os.Remove(filepath.Join(targetModulesDir, filepath.FromSlash(relPath))); err != nil && !os.IsNotExist(err) {
			return 0, err
		}
		updated++
	}

	return updated, nil
}

func vfxPersistentImportComplete(baseObj, lockObj map[string]any) bool {
	if !vfxPersistentRowsHaveKeys(baseObj) {
		return false
	}
	expected := map[string]int{
		"vfx_persistent:blankradius5":  47,
		"vfx_persistent:blankradius10": 48,
		"vfx_persistent:blankradius15": 49,
		"vfx_persistent:blankradius20": 50,
		"vfx_persistent:blankradius25": 51,
		"vfx_persistent:blankradius30": 52,
	}
	for key, want := range expected {
		raw, ok := lockObj[key]
		if !ok {
			return false
		}
		got, err := asInt(raw)
		if err != nil || got != want {
			return false
		}
	}
	return true
}

func synthesizeVFXPersistentKeys(baseObj map[string]any) (map[string]any, error) {
	rawRows, ok := baseObj["rows"].([]any)
	if !ok {
		return map[string]any{}, nil
	}
	lockObj := map[string]any{}
	for _, raw := range rawRows {
		row, ok := raw.(map[string]any)
		if !ok {
			continue
		}
		label, _ := row["LABEL"].(string)
		if label == "" {
			continue
		}
		key := "vfx_persistent:" + strings.ToLower(label)
		row["key"] = key
		if rawID, ok := row["id"]; ok {
			lockObj[key] = rawID
		}
	}
	return lockObj, nil
}

func vfxPersistentRowsHaveKeys(baseObj map[string]any) bool {
	rawRows, ok := baseObj["rows"].([]any)
	if !ok {
		return false
	}
	for _, raw := range rawRows {
		row, ok := raw.(map[string]any)
		if !ok {
			return false
		}
		key, _ := row["key"].(string)
		if key == "" {
			return false
		}
	}
	return true
}

func equalStringSlices(left, right []string) bool {
	if len(left) != len(right) {
		return false
	}
	for i := range left {
		if left[i] != right[i] {
			return false
		}
	}
	return true
}
