package inject

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"time"
)

// Platform 平台类型
type Platform string

const (
	PlatformAndroid Platform = "android"
	PlatformWindows Platform = "windows"
	PlatformLinux   Platform = "linux"
	PlatformIOS     Platform = "ios"
)

// Arch 架构类型
type Arch string

const (
	ArchX86       Arch = "x86"
	ArchX64       Arch = "x64"
	ArchARM      Arch = "arm"
	ArchARM64    Arch = "arm64"
	ArchUniversal Arch = "universal"
)

// InjectConfig 注入配置
type InjectConfig struct {
	Platform         Platform `json:"platform"`
	Arch             Arch     `json:"arch"`
	TemplateName     string   `json:"template_name"`
	ShowVerification bool     `json:"show_verification"`
	ShowAd           bool     `json:"show_ad"`
	AdURL            string   `json:"ad_url"`
	CountdownSeconds int      `json:"countdown_seconds"`
	AppName          string   `json:"app_name"`
	VerifyURL        string   `json:"verify_url"`
	AppKey           string   `json:"app_key"`
}

// InjectResult 注入结果
type InjectResult struct {
	Success     bool   `json:"success"`
	ResultFile  string `json:"result_file"`
	ResultSize  int64  `json:"result_size"`
	Error       string `json:"error"`
	ProcessTime int64  `json:"process_time"` // 处理耗时（毫秒）
}

// InjectService 注入服务
type InjectService struct {
	ApktoolPath  string
	KeystorePath string
	KeystorePass string
	KeystoreAlias string
	KeyPass      string
	ApksignerPath string
	WorkDir      string
}

// NewInjectService 创建注入服务
func NewInjectService(workDir string) *InjectService {
	// 确保 workDir 是绝对路径
	absWorkDir, err := filepath.Abs(workDir)
	if err != nil {
		absWorkDir = workDir
	}

	return &InjectService{
		WorkDir:      absWorkDir,
		ApktoolPath:  getEnvOrDefault("APKTOOL_PATH", "apktool"),
		KeystorePath: getEnvOrDefault("KEYSTORE_PATH", ""),
		KeystorePass: getEnvOrDefault("KEYSTORE_PASS", "123456"),
		KeystoreAlias: getEnvOrDefault("KEYSTORE_ALIAS", "mykey"),
		KeyPass:      getEnvOrDefault("KEY_PASS", "123456"),
		ApksignerPath: getEnvOrDefault("APKSIGNER_PATH", "apksigner"),
	}
}

func getEnvOrDefault(key, defaultValue string) string {
	if value := os.Getenv(key); value != "" {
		return value
	}
	return defaultValue
}

// Inject 执行注入
func (s *InjectService) Inject(inputFile string, config InjectConfig) (*InjectResult, error) {
	startTime := time.Now()

	// 创建工作目录
	taskID := fmt.Sprintf("inject_%d", time.Now().UnixNano())
	taskDir := filepath.Join(s.WorkDir, taskID)
	if err := os.MkdirAll(taskDir, 0755); err != nil {
		return nil, fmt.Errorf("创建工作目录失败: %v", err)
	}
	defer os.RemoveAll(taskDir) // 清理工作目录

	var result *InjectResult
	var err error

	switch config.Platform {
	case PlatformAndroid:
		result, err = s.injectAndroid(inputFile, config, taskDir)
	case PlatformWindows:
		result, err = s.injectWindows(inputFile, config, taskDir)
	case PlatformLinux:
		result, err = s.injectLinux(inputFile, config, taskDir)
	case PlatformIOS:
		result, err = s.injectIOS(inputFile, config, taskDir)
	default:
		err = fmt.Errorf("不支持的平台: %s", config.Platform)
	}

	if err != nil {
		return &InjectResult{
			Success:     false,
			Error:       err.Error(),
			ProcessTime: time.Since(startTime).Milliseconds(),
		}, err
	}

	result.ProcessTime = time.Since(startTime).Milliseconds()
	return result, nil
}

// injectAndroid Android APK 注入
func (s *InjectService) injectAndroid(inputFile string, config InjectConfig, taskDir string) (*InjectResult, error) {
	log.Printf("[INFO] 开始 Android APK 注入: %s", inputFile)

	// 1. 反编译 APK
	decompileDir := filepath.Join(taskDir, "decompiled")
	if err := s.decompileAPK(inputFile, decompileDir); err != nil {
		return nil, fmt.Errorf("反编译失败: %v", err)
	}

	// 2. 复制注入模板的 smali 文件
	templateDir := filepath.Join("inject", "android")
	if err := s.mergeSmali(templateDir, decompileDir); err != nil {
		return nil, fmt.Errorf("合并 smali 失败: %v", err)
	}

	// 3. 配置注入参数
	if err := s.configureAndroid(decompileDir, config); err != nil {
		return nil, fmt.Errorf("配置失败: %v", err)
	}

	// 4. 修改 AndroidManifest.xml
	if err := s.modifyAndroidManifest(decompileDir); err != nil {
		return nil, fmt.Errorf("修改 AndroidManifest 失败: %v", err)
	}

	// 5. 回编译 APK
	unsignedAPK := filepath.Join(taskDir, "unsigned.apk")
	if err := s.recompileAPK(decompileDir, unsignedAPK); err != nil {
		return nil, fmt.Errorf("回编译失败: %v", err)
	}

	// 6. 签名 APK
	signedAPK := filepath.Join(taskDir, "signed.apk")
	if err := s.signAPK(unsignedAPK, signedAPK); err != nil {
		return nil, fmt.Errorf("签名失败: %v", err)
	}

	// 7. 获取结果文件信息
	fileInfo, err := os.Stat(signedAPK)
	if err != nil {
		return nil, fmt.Errorf("获取文件信息失败: %v", err)
	}

	// 8. 复制结果文件到输出目录
	outputDir := filepath.Join("uploads", "inject")
	if err := os.MkdirAll(outputDir, 0755); err != nil {
		return nil, fmt.Errorf("创建输出目录失败: %v", err)
	}

	outputFile := filepath.Join(outputDir, fmt.Sprintf("injected_%d.apk", time.Now().Unix()))
	if err := copyFile(signedAPK, outputFile); err != nil {
		return nil, fmt.Errorf("复制结果文件失败: %v", err)
	}

	log.Printf("[INFO] Android APK 注入完成: %s", outputFile)

	return &InjectResult{
		Success:    true,
		ResultFile: "/" + strings.ReplaceAll(outputFile, "\\", "/"),
		ResultSize: fileInfo.Size(),
	}, nil
}

// injectWindows Windows PE 注入 (占位)
func (s *InjectService) injectWindows(inputFile string, config InjectConfig, taskDir string) (*InjectResult, error) {
	return nil, fmt.Errorf("Windows 平台注入暂未实现")
}

// injectLinux Linux ELF 注入 (占位)
func (s *InjectService) injectLinux(inputFile string, config InjectConfig, taskDir string) (*InjectResult, error) {
	return nil, fmt.Errorf("Linux 平台注入暂未实现")
}

// injectIOS iOS IPA 注入 (占位)
func (s *InjectService) injectIOS(inputFile string, config InjectConfig, taskDir string) (*InjectResult, error) {
	return nil, fmt.Errorf("iOS 平台注入暂未实现")
}

// decompileAPK 反编译 APK
func (s *InjectService) decompileAPK(apkFile, outputDir string) error {
	cmd := exec.Command("java", "-jar", s.ApktoolPath, "d", apkFile, "-o", outputDir, "-f")
	output, err := cmd.CombinedOutput()
	if err != nil {
		return fmt.Errorf("apktool d 失败: %v, output: %s", err, string(output))
	}
	log.Printf("[DEBUG] decompile output: %s", string(output))
	return nil
}

// recompileAPK 回编译 APK
func (s *InjectService) recompileAPK(decompileDir, outputFile string) error {
	cmd := exec.Command("java", "-jar", s.ApktoolPath, "b", decompileDir, "-o", outputFile)
	output, err := cmd.CombinedOutput()
	if err != nil {
		return fmt.Errorf("apktool b 失败: %v, output: %s", err, string(output))
	}
	log.Printf("[DEBUG] recompile output: %s", string(output))
	return nil
}

// signAPK 签名 APK
func (s *InjectService) signAPK(unsignedAPK, signedAPK string) error {
	// 如果没有配置 keystore，使用测试签名
	if s.KeystorePath == "" {
		log.Printf("[WARN] 未配置 keystore，使用 zipalign 对齐")
		// 使用 zipalign 对齐
		cmd := exec.Command("zipalign", "-v", "-p", "4", unsignedAPK, signedAPK)
		output, err := cmd.CombinedOutput()
		if err != nil {
			return fmt.Errorf("zipalign 失败: %v, output: %s", err, string(output))
		}
		return nil
	}

	// 使用 apksigner 签名
	cmd := exec.Command(s.ApksignerPath, "sign",
		"--ks", s.KeystorePath,
		"--ks-key-alias", s.KeystoreAlias,
		"--ks-pass", "pass:"+s.KeystorePass,
		"--key-pass", "pass:"+s.KeyPass,
		"--out", signedAPK,
		unsignedAPK)
	output, err := cmd.CombinedOutput()
	if err != nil {
		return fmt.Errorf("apksigner 签名失败: %v, output: %s", err, string(output))
	}
	log.Printf("[DEBUG] sign output: %s", string(output))
	return nil
}

// mergeSmali 合并 smali 文件
func (s *InjectService) mergeSmali(templateDir, decompileDir string) error {
	// 复制模板 smali 文件到反编译目录
	smaliDirs := []string{"smali", "smali_classes2", "smali_classes3"}
	for _, smaliDir := range smaliDirs {
		srcSmali := filepath.Join(templateDir, smaliDir)
		if _, err := os.Stat(srcSmali); os.IsNotExist(err) {
			continue
		}

		dstSmali := filepath.Join(decompileDir, smaliDir)
		if smaliDir == "smali" {
			// 模板的 smali 直接覆盖
			if err := copyDir(srcSmali, dstSmali); err != nil {
				return err
			}
		} else {
			// 其他 smali_classes 需要合并
			if err := copyDir(srcSmali, dstSmali); err != nil {
				return err
			}
		}
	}
	return nil
}

// configureAndroid 配置 Android 注入参数
func (s *InjectService) configureAndroid(decompileDir string, config InjectConfig) error {
	// 查找并修改 HookApplication.java 中的配置
	hookAppPath := filepath.Join(decompileDir, "smali", "com", "example", "shell", "HookApplication.smali")
	if _, err := os.Stat(hookAppPath); os.IsNotExist(err) {
		log.Printf("[WARN] HookApplication.smali 不存在，跳过配置")
		return nil
	}

	// 读取文件内容
	content, err := ioutil.ReadFile(hookAppPath)
	if err != nil {
		return err
	}

	contentStr := string(content)

	// 替换配置参数
	replacements := map[string]string{
		"[OpenClassName]":          config.AppName,
		"\"https://example.com\"":  fmt.Sprintf("\"%s\"", config.VerifyURL),
		"[AppKey]":                 config.AppKey,
	}

	for old, new := range replacements {
		contentStr = strings.ReplaceAll(contentStr, old, new)
	}

	// 写回文件
	return ioutil.WriteFile(hookAppPath, []byte(contentStr), 0644)
}

// modifyAndroidManifest 修改 AndroidManifest.xml
func (s *InjectService) modifyAndroidManifest(decompileDir string) error {
	manifestPath := filepath.Join(decompileDir, "AndroidManifest.xml")
	content, err := ioutil.ReadFile(manifestPath)
	if err != nil {
		return err
	}

	contentStr := string(content)

	// 检查是否已有 android:name
	if strings.Contains(contentStr, "android:name=") {
		// 替换现有的 android:name
		re := strings.NewReplacer(
			`android:name="android.app.Application"`, `android:name="com.example.shell.HookApplication"`,
		)
		contentStr = re.Replace(contentStr)
	} else {
		// 在 <application 标签添加 android:name
		contentStr = strings.Replace(contentStr, "<application", `<application android:name="com.example.shell.HookApplication"`, 1)
	}

	return ioutil.WriteFile(manifestPath, []byte(contentStr), 0644)
}

// copyFile 复制文件
func copyFile(src, dst string) error {
	input, err := ioutil.ReadFile(src)
	if err != nil {
		return err
	}
	return ioutil.WriteFile(dst, input, 0644)
}

// copyDir 复制目录
func copyDir(src, dst string) error {
	// 确保目标目录存在
	if err := os.MkdirAll(dst, 0755); err != nil {
		return err
	}

	entries, err := ioutil.ReadDir(src)
	if err != nil {
		return err
	}

	for _, entry := range entries {
		srcPath := filepath.Join(src, entry.Name())
		dstPath := filepath.Join(dst, entry.Name())

		if entry.IsDir() {
			if err := copyDir(srcPath, dstPath); err != nil {
				return err
			}
		} else {
			if err := copyFile(srcPath, dstPath); err != nil {
				return err
			}
		}
	}
	return nil
}

// GetSupportedPlatforms 获取支持的平台和架构
func GetSupportedPlatforms() map[string][]string {
	return map[string][]string{
		"android": {"x86", "x64", "arm", "arm64"},
		"windows": {"x86", "x64"},
		"linux":   {"x86", "x64", "arm", "arm64"},
		"ios":     {"arm", "arm64"},
	}
}

// DetectPlatform 检测文件平台
func DetectPlatform(filename string) (Platform, error) {
	ext := strings.ToLower(filepath.Ext(filename))
	switch ext {
	case ".apk":
		return PlatformAndroid, nil
	case ".exe", ".dll":
		return PlatformWindows, nil
	case ".so", "", ".elf":
		if strings.Contains(strings.ToLower(filename), "linux") || ext == ".so" {
			return PlatformLinux, nil
		}
	case ".ipa":
		return PlatformIOS, nil
	}

	// 根据文件名猜测
	lowerName := strings.ToLower(filename)
	if strings.Contains(lowerName, "android") || strings.Contains(lowerName, "apk") {
		return PlatformAndroid, nil
	}
	if strings.Contains(lowerName, "windows") || strings.Contains(lowerName, "win") || strings.Contains(lowerName, ".exe") {
		return PlatformWindows, nil
	}
	if strings.Contains(lowerName, "linux") || strings.Contains(lowerName, ".so") {
		return PlatformLinux, nil
	}
	if strings.Contains(lowerName, "ios") || strings.Contains(lowerName, ".ipa") {
		return PlatformIOS, nil
	}

	return "", fmt.Errorf("无法检测文件平台: %s", filename)
}

// ToJSON 转换为 JSON
func (c *InjectConfig) ToJSON() string {
	data, _ := json.Marshal(c)
	return string(data)
}

// ParseConfig 从 JSON 解析配置
func ParseConfig(jsonStr string) (*InjectConfig, error) {
	var config InjectConfig
	err := json.Unmarshal([]byte(jsonStr), &config)
	return &config, err
}
