package backend

import (
	"bytes"
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"strings"

	"github.com/wailsapp/wails/v2/pkg/runtime"
)

func (a *App) SelectFile(title string, defaultDir string, filter string) (string, error) {
	return runtime.OpenFileDialog(a.ctx, runtime.OpenDialogOptions{
		Title:            title,
		DefaultDirectory: defaultDir,
		Filters:          []runtime.FileFilter{{Pattern: filter}},
	})
}

func (a *App) SelectDirectory(title string, defaultDir string) (string, error) {
	return runtime.OpenDirectoryDialog(a.ctx, runtime.OpenDialogOptions{
		Title:            title,
		DefaultDirectory: defaultDir,
	})
}

func (a *App) CheckGenPs1Exists(filePath string) (bool, error) {
	if filePath == "" {
		return false, fmt.Errorf("file path is empty")
	}

	_, err := os.Stat(filePath)
	if err != nil {
		if os.IsNotExist(err) {
			return false, nil
		}
		return false, err
	}
	return true, nil
}

func (a *App) ReadGoModModule(filePath string) (string, error) {
	if filePath == "" {
		return "", fmt.Errorf("file path is empty")
	}

	dirPath := filepath.Dir(filePath)
	goModPath := filepath.Join(dirPath, "go.mod")

	content, err := os.ReadFile(goModPath)
	if err != nil {
		return "", fmt.Errorf("go.mod not found: %w", err)
	}

	lines := strings.Split(string(content), "\n")
	for _, line := range lines {
		line = strings.TrimSpace(line)
		if strings.HasPrefix(line, "module ") {
			moduleName := strings.TrimPrefix(line, "module ")
			moduleName = strings.TrimSpace(moduleName)
			return moduleName, nil
		}
	}

	return "", fmt.Errorf("module declaration not found in go.mod")
}

func (a *App) ExecuteGenPs1(genPs1Path string, dbName string, targetPath string, modelPackagePath string) (string, error) {
	if genPs1Path == "" {
		return "", fmt.Errorf("gen.ps1 path is empty")
	}
	if dbName == "" {
		return "", fmt.Errorf("database name is empty")
	}

	if _, err := os.Stat(genPs1Path); err != nil {
		if os.IsNotExist(err) {
			return "", fmt.Errorf("gen.ps1 not found")
		}
		return "", fmt.Errorf("error checking gen.ps1: %w", err)
	}

	dirPath := filepath.Dir(genPs1Path)

	psPath, err := exec.LookPath("powershell.exe")
	if err != nil {
		return "", fmt.Errorf("PowerShell not found: %w", err)
	}

	args := []string{
		"-NoProfile",
		"-ExecutionPolicy", "Bypass",
		"-Command",
		fmt.Sprintf("Set-Location -Path '%s'; & .\\gen.ps1 -dbName '%s'", dirPath, dbName),
	}

	cmd := exec.Command(psPath, args...)

	output, err := cmd.CombinedOutput()
	if err != nil {
		return "", fmt.Errorf("script execution failed: %w\nOutput: %s", err, string(output))
	}

	if targetPath != "" {
		sourceDir := filepath.Join(dirPath, dbName)
		if _, err := os.Stat(sourceDir); err == nil {
			modelSource := filepath.Join(sourceDir, "model")
			querySource := filepath.Join(sourceDir, "query")

			modelTarget := filepath.Join(targetPath, "model")
			queryTarget := filepath.Join(targetPath, "query")

			if _, err := os.Stat(modelSource); err == nil {
				if err := copyDir(modelSource, modelTarget); err != nil {
					return string(output), fmt.Errorf("failed to copy model directory: %w", err)
				}
			}

			if _, err := os.Stat(querySource); err == nil {
				if err := copyDir(querySource, queryTarget); err != nil {
					return string(output), fmt.Errorf("failed to copy query directory: %w", err)
				}
				if modelPackagePath != "" {
					if err := replaceImportPaths(queryTarget, dbName, modelPackagePath, a.settings.DefaultQueryPackagePath); err != nil {
						return string(output), fmt.Errorf("failed to replace import paths: %w", err)
					}
				}
			}
		}
	}

	return string(output), nil
}

func replaceImportPaths(queryDir string, dbName string, newPackagePath string, basePath string) error {
	err := filepath.Walk(queryDir, func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}

		if !info.IsDir() && strings.HasSuffix(path, ".gen.go") {
			if err := replaceImportInFile(path, dbName, newPackagePath, basePath); err != nil {
				return err
			}
		}

		return nil
	})

	return err
}

func replaceImportInFile(filePath string, dbName string, newPackagePath string, basePath string) error {
	content, err := os.ReadFile(filePath)
	if err != nil {
		return err
	}

	if basePath == "" {
		basePath = "git.hlsq.asia/mmorpg"
	}

	oldImport := fmt.Sprintf(`"%s/%s/model"`, basePath, dbName)
	newImport := fmt.Sprintf(`"%s"`, newPackagePath)

	newContent := bytes.ReplaceAll(content, []byte(oldImport), []byte(newImport))

	return os.WriteFile(filePath, newContent, 0644)
}
