package main

import (
	"bufio"
	"bytes"
	"encoding/base64"
	"encoding/binary"
	"encoding/json"
	"fmt"
	"io"
	"math/rand"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"runtime"
	"strings"
	"syscall"
	"time"
)

// ANSI color codes
const (
	cReset   = "\x1b[0m"
	cCyan    = "\x1b[36m"
	cYellow  = "\x1b[33m"
	cGreen   = "\x1b[32m"
	cRed     = "\x1b[31m"
	cMagenta = "\x1b[35m"
	cBlue    = "\x1b[34m"

	cCyanB    = "\x1b[96m"
	cYellowB  = "\x1b[93m"
	cGreenB   = "\x1b[92m"
	cRedB     = "\x1b[91m"
	cMagentaB = "\x1b[95m"
	cBlueB    = "\x1b[94m"
)

func main() {
	if runtime.GOOS == "windows" {
		runHidden("cmd.exe", "/c", "chcp", "65001")
	}

	typoraPath := ""
	for {
		typoraPath = chooseTyporaDir()
		exePath := filepath.Join(typoraPath, "Typora.exe")
		resourcesPath := filepath.Join(typoraPath, "resources")
		asarPath := filepath.Join(resourcesPath, "app.asar")

		if _, err := os.Stat(exePath); os.IsNotExist(err) {
			fmt.Printf("%s❌ 错误：该目录下没有找到 Typora.exe！%s\n", cRed, cReset)
			fmt.Printf("%s请确保选择的是 Typora 的根安装目录。%s\n\n", cYellow, cReset)
			continue
		}

		if _, err := os.Stat(asarPath); os.IsNotExist(err) {
			// Check for existing activation: app/ directory or app.asar.bak
			appDirCheck := filepath.Join(resourcesPath, "app")
			asarBakCheck := filepath.Join(resourcesPath, "app.asar.bak")
			_, errBak := os.Stat(asarBakCheck)
			hasBak := errBak == nil
			info, errAppDir := os.Stat(appDirCheck)
			hasAppDir := errAppDir == nil && info.IsDir()

			if hasBak || hasAppDir {
				fmt.Printf("%s\n⚠️  检测到 Typora 已经被激活过！%s\n", cYellowB, cReset)
				fmt.Printf("%s是否执行回滚还原？[Y/N]：%s", cCyan, cReset)
				choice := strings.TrimSpace(strings.ToUpper(readLine()))
				if choice == "Y" {
					rollbackTypora(typoraPath)
				} else {
					fmt.Printf("%s已取消回滚，退出脚本。%s\n", cGreen, cReset)
					quit(0)
				}
			} else {
				fmt.Printf("%s❌ 错误：未找到 resources/app.asar 文件！%s\n", cRed, cReset)
				fmt.Printf("%s请确认这是完整的 Typora 安装目录。%s\n\n", cYellow, cReset)
				continue
			}
		}

		fmt.Printf("%s✅ 路径验证成功！准备开始激活...%s\n", cGreen, cReset)
		break
	}

	machineCode, email := getMachineCodeAndEmail()
	atobMachineCode := map[string]string{}
	decoded, err := base64.StdEncoding.DecodeString(machineCode)
	if err != nil {
		fmt.Printf("%s💥 机器码解码失败：%s%s\n", cRed, err, cReset)
		quit(1)
	}
	json.Unmarshal(decoded, &atobMachineCode)

	fmt.Printf("%sdeviceId: %s%s\n", cBlueB, atobMachineCode["l"], cReset)
	fmt.Printf("%sfingerprint: %s%s\n", cBlueB, atobMachineCode["i"], cReset)
	fmt.Printf("%sversion: %s%s\n", cBlueB, atobMachineCode["v"], cReset)

	nowDateStr := getNowDateStr()
	enableHookDebug := false

	closeTyporaProcesses()
	time.Sleep(300 * time.Millisecond)

	resourcesPath := filepath.Join(typoraPath, "resources")
	asarPath := filepath.Join(resourcesPath, "app.asar")
	appDir := filepath.Join(resourcesPath, "app")
	appBakDir := filepath.Join(resourcesPath, "app.bak")
	asarBakPath := filepath.Join(resourcesPath, "app.asar.bak")
	typoraExe := filepath.Join(typoraPath, "Typora.exe")
	launchDistJS := filepath.Join(appDir, "launch.dist.js")

	err = func() error {
		clearScreen()
		fmt.Printf("%s\n✨ 正在启动 Typora 激活脚本...%s\n", cYellowB, cReset)
		fmt.Printf("%s\n==== 开始处理... ====%s\n", cGreenB, cReset)
		fmt.Printf("%s\n一、环境配置...%s\n", cBlueB, cReset)

		if _, err := os.Stat(appDir); err == nil {
			os.RemoveAll(appDir)
		}

		fmt.Printf("%s解包 app.asar%s\n", cBlue, cReset)
		if err := extractAsar(asarPath, appDir); err != nil {
			return fmt.Errorf("解包 app.asar 失败: %w", err)
		}

		fmt.Printf("%s备份 app 目录%s\n", cBlue, cReset)
		if err := copyDir(appDir, appBakDir); err != nil {
			return fmt.Errorf("备份 app 目录失败: %w", err)
		}

		fmt.Printf("%s备份原始 app.asar%s\n", cBlue, cReset)
		if err := os.Rename(asarPath, asarBakPath); err != nil {
			return fmt.Errorf("备份 app.asar 失败: %w", err)
		}

		fmt.Printf("%s备份原始 Typora.exe%s\n", cBlue, cReset)
		if err := copyFile(typoraExe, typoraExe+".bak"); err != nil {
			return fmt.Errorf("备份 Typora.exe 失败: %w", err)
		}

		fmt.Printf("%s配置 Electron Fuses...%s\n", cBlue, cReset)
		if err := flipElectronFuse(typoraExe); err != nil {
			return fmt.Errorf("配置 Electron Fuses 失败: %w", err)
		}

		fmt.Printf("%s✅ 环境配置完成！%s\n", cGreenB, cReset)
		fmt.Printf("%s\n二、注入授权模块...%s\n", cBlueB, cReset)

		contentBytes, err := os.ReadFile(launchDistJS)
		if err != nil {
			return fmt.Errorf("读取 launch.dist.js 失败: %w", err)
		}
		content := string(contentBytes)

		injectCode := getInsertCode(enableHookDebug, atobMachineCode, email, nowDateStr)

		re := regexp.MustCompile(`require\s*\((?:[^()]|\([^()]*\))*\)\s*;`)
		match := re.FindStringIndex(content)
		if match != nil {
			content = content[:match[1]] + injectCode + content[match[1]:]
		} else {
			content = injectCode + content
		}

		if err := os.WriteFile(launchDistJS, []byte(content), 0644); err != nil {
			return fmt.Errorf("写入 launch.dist.js 失败: %w", err)
		}

		fmt.Printf("%s✅ 注入完成！%s\n", cGreenB, cReset)
		fmt.Printf("%s\n三、写入授权...%s\n", cBlueB, cReset)

		writeRegValue("HKCU\\Software\\Typora", "SLicense", "RHJlYW1OeWE=#0#1/1/2059")
		writeRegValue("HKCU\\Software\\Typora", "IDate", nowDateStr)

		fmt.Printf("%s✅ 授权写入成功！%s\n", cGreenB, cReset)
		fmt.Printf("%s\n🎉 全部完成！使用愉快！%s\n", cGreenB, cReset)
		fmt.Printf("%s🔑 激活码：%s%s\n", cMagentaB, generateRegCode(), cReset)

		return nil
	}()

	if err != nil {
		fmt.Printf("%s\n💥 错误：%s%s\n", cRed, err, cReset)
		fmt.Printf("%s\n🔄 正在执行自动回滚...%s\n", cYellowB, cReset)
		rollbackTypora(typoraPath)
	}

	quit(0)
}

// ========== Pickle / ASAR Extraction ==========

func extractAsar(asarPath, destDir string) error {
	data, err := os.ReadFile(asarPath)
	if err != nil {
		return err
	}
	if len(data) < 8 {
		return fmt.Errorf("asar 文件太小")
	}

	headerPayloadSize := int(binary.LittleEndian.Uint32(data[0:4]))
	if headerPayloadSize != 4 {
		return fmt.Errorf("非预期的 asar header 格式：payload size = %d", headerPayloadSize)
	}

	headerSize := int(binary.LittleEndian.Uint32(data[4:8]))
	if 8+headerSize > len(data) {
		return fmt.Errorf("asar header 超出文件范围")
	}

	headerPickle := data[8 : 8+headerSize]
	if len(headerPickle) < 8 {
		return fmt.Errorf("header pickle 太小")
	}

	strLen := int(int32(binary.LittleEndian.Uint32(headerPickle[4:8])))
	if strLen < 0 || 8+strLen > len(headerPickle) {
		return fmt.Errorf("非预期的 JSON 字符串长度: %d", strLen)
	}

	jsonStr := string(headerPickle[8 : 8+strLen])

	var headerJSON map[string]interface{}
	if err := json.Unmarshal([]byte(jsonStr), &headerJSON); err != nil {
		return fmt.Errorf("解析 ASAR header JSON 失败: %w", err)
	}

	filesObj, ok := headerJSON["files"].(map[string]interface{})
	if !ok {
		return fmt.Errorf("ASAR header 缺少 files 对象")
	}

	if err := os.MkdirAll(destDir, 0755); err != nil {
		return fmt.Errorf("创建目标目录失败: %w", err)
	}

	dataStart := int64(8 + headerSize)
	var walk func(basePath string, files map[string]interface{}) error
	walk = func(basePath string, files map[string]interface{}) error {
		for name, v := range files {
			info, ok := v.(map[string]interface{})
			if !ok {
				continue
			}
			fullPath := filepath.Join(basePath, name)

			if subFiles, ok := info["files"]; ok {
				subFilesMap, _ := subFiles.(map[string]interface{})
				if err := os.MkdirAll(fullPath, 0755); err != nil {
					return err
				}
				if err := walk(fullPath, subFilesMap); err != nil {
					return err
				}
				continue
			}

			if link, ok := info["link"]; ok {
				linkStr, _ := link.(string)
				os.Remove(fullPath)
				os.Symlink(linkStr, fullPath)
				continue
			}

			sizeVal, ok1 := info["size"]
			offsetStr, _ := info["offset"].(string)
			if !ok1 || offsetStr == "" {
				continue
			}

			intSize := int(sizeVal.(float64))
			if intSize == 0 {
				if err := os.MkdirAll(filepath.Dir(fullPath), 0755); err != nil {
					return err
				}
				os.WriteFile(fullPath, []byte{}, 0644)
				continue
			}

			offset := int64(0)
			fmt.Sscanf(offsetStr, "%d", &offset)
			dataOffset := dataStart + offset

			if dataOffset+int64(intSize) > int64(len(data)) {
				return fmt.Errorf("文件 %s 数据超出范围", fullPath)
			}

			if err := os.MkdirAll(filepath.Dir(fullPath), 0755); err != nil {
				return err
			}
			if err := os.WriteFile(fullPath, data[dataOffset:dataOffset+int64(intSize)], 0644); err != nil {
				return err
			}

			if execOk, _ := info["executable"].(bool); execOk {
				os.Chmod(fullPath, 0755)
			}
		}
		return nil
	}

	return walk(destDir, filesObj)
}

// ========== File Utilities ==========

func copyFile(src, dst string) error {
	s, err := os.Open(src)
	if err != nil {
		return err
	}
	defer s.Close()
	d, err := os.Create(dst)
	if err != nil {
		return err
	}
	defer d.Close()
	_, err = io.Copy(d, s)
	return err
}

func copyDir(src, dest string) error {
	return filepath.Walk(src, func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}
		relPath, _ := filepath.Rel(src, path)
		destPath := filepath.Join(dest, relPath)
		if info.IsDir() {
			return os.MkdirAll(destPath, info.Mode())
		}
		return copyFile(path, destPath)
	})
}

// ========== Electron Fuse Flip ==========

const fuseSentinel = "dL7pKGdnNz796PbbjQWNKmHXBZaB9tsX"

func flipElectronFuse(exePath string) error {
	data, err := os.ReadFile(exePath)
	if err != nil {
		return fmt.Errorf("读取 EXE 失败: %w", err)
	}

	sentinelIdx := bytes.Index(data, []byte(fuseSentinel))
	if sentinelIdx == -1 {
		return fmt.Errorf("未找到 Electron fuse sentinel")
	}

	fuseOffset := sentinelIdx + len(fuseSentinel)
	if fuseOffset+2 >= len(data) {
		return fmt.Errorf("fuse 数据不完整")
	}

	version := data[fuseOffset]
	length := int(data[fuseOffset+1])

	// FuseV1Options: index 5 = OnlyLoadAppFromAsar
	// Values: 0x30=DISABLE, 0x31=ENABLE, 0x72=REMOVED, 0x90=INHERIT
	const OnlyLoadAppFromAsar = 5
	if version == 1 && length > OnlyLoadAppFromAsar {
		if fuseOffset+2+length > len(data) {
			return fmt.Errorf("fuse wire 数据超出范围")
		}
		data[fuseOffset+2+OnlyLoadAppFromAsar] = 0x30 // DISABLE
	} else {
		return fmt.Errorf("不支持的 fuse 版本: %d, length: %d", version, length)
	}

	if err := os.WriteFile(exePath, data, 0644); err != nil {
		return fmt.Errorf("写入 EXE 失败: %w", err)
	}
	return nil
}

// ========== Registry Operations ==========

func writeRegValue(key, name, value string) {
	if runtime.GOOS != "windows" {
		return
	}
	cmd := exec.Command("reg", "add", key, "/v", name, "/t", "REG_SZ", "/d", value, "/f")
	cmd.Stdout = nil
	cmd.Stderr = nil
	cmd.Stdin = nil
	cmd.SysProcAttr = windowsHide()
	if err := cmd.Run(); err != nil {
		panic(fmt.Errorf("reg add %s\\%s 失败", key, name))
	}
}

func deleteRegValue(key, name string) {
	if runtime.GOOS != "windows" {
		return
	}
	cmd := exec.Command("reg", "delete", key, "/v", name, "/f")
	cmd.Stdout = nil
	stderr := &strings.Builder{}
	cmd.Stderr = stderr
	cmd.Stdin = nil
	cmd.SysProcAttr = windowsHide()
	if err := cmd.Run(); err != nil {
		stderrStr := stderr.String()
		if strings.Contains(stderrStr, "unable to find") {
			return
		}
		fmt.Printf("%s⚠ 删除注册表值 %s 失败（可忽略）: %s%s\n", cYellow, name, strings.TrimSpace(stderrStr), cReset)
	}
}

// ========== Helper Functions ==========

func windowsHide() *syscall.SysProcAttr {
	return &syscall.SysProcAttr{HideWindow: true}
}

func runHidden(name string, args ...string) {
	cmd := exec.Command(name, args...)
	cmd.Stdout = nil
	cmd.Stderr = nil
	cmd.Stdin = nil
	cmd.SysProcAttr = windowsHide()
	cmd.Run()
}

func clearScreen() {
	fmt.Print("\x1b[2J\x1b[H")
}

func quit(code int) {
	fmt.Printf("%s\n按任意键退出...%s", cCyan, cReset)
	bufio.NewReader(os.Stdin).ReadBytes('\n')
	os.Exit(code)
}

func readLine() string {
	reader := bufio.NewReader(os.Stdin)
	line, _ := reader.ReadString('\n')
	return strings.TrimRight(line, "\r\n")
}

func generateRegCode() string {
	chars := "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
	code := "+"
	for i := 0; i < 8; i++ {
		code += string(chars[rand.Intn(len(chars))])
	}
	return code + "#"
}

func getNowDateStr() string {
	now := time.Now()
	return fmt.Sprintf("%02d/%02d/%d", now.Month(), now.Day(), now.Year())
}

func closeTyporaProcesses() {
	fmt.Printf("%s正在关闭 Typora 进程...%s\n", cBlue, cReset)
	runHidden("taskkill", "/IM", "Typora.exe")
	time.Sleep(500 * time.Millisecond)
	cmd := exec.Command("taskkill", "/F", "/IM", "Typora.exe")
	cmd.Stdout = nil
	cmd.Stderr = nil
	cmd.Stdin = nil
	cmd.SysProcAttr = windowsHide()
	if cmd.Run() == nil {
		fmt.Printf("%s✅ 已关闭所有 Typora 进程%s\n", cGreen, cReset)
	} else {
		fmt.Printf("%s⚠ 未检测到运行中的 Typora.exe%s\n", cYellow, cReset)
	}
}

// ========== Configuration Cache ==========

type cacheConfig struct {
	Path        string `json:"path"`
	MachineCode string `json:"machineCode"`
	Email       string `json:"email"`
}

func configPath() string {
	home, _ := os.UserHomeDir()
	return filepath.Join(home, ".typora_crack_config.json")
}

func readCache() cacheConfig {
	data, err := os.ReadFile(configPath())
	if err != nil {
		return cacheConfig{}
	}
	var cfg cacheConfig
	json.Unmarshal(data, &cfg)
	if cfg.Path != "" {
		if _, err := os.Stat(filepath.Join(cfg.Path, "Typora.exe")); os.IsNotExist(err) {
			cfg.Path = ""
		}
	}
	return cfg
}

func saveCache(cfg cacheConfig) {
	data, _ := json.MarshalIndent(cfg, "", "  ")
	os.WriteFile(configPath(), data, 0644)
}

// ========== Typora Path Detection ==========

func readRegPath() string {
	if runtime.GOOS != "windows" {
		return ""
	}
	cmd := exec.Command("reg", "query",
		`HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\Typora.exe`,
		"/ve")
	cmd.Stdin = nil
	cmd.SysProcAttr = windowsHide()
	out, err := cmd.Output()
	if err != nil {
		return ""
	}

	output := string(out)
	lines := strings.Split(output, "\n")
	for _, line := range lines {
		idx := strings.Index(line, "REG_SZ")
		if idx == -1 {
			idx = strings.Index(line, "REG_EXPAND_SZ")
			if idx == -1 {
				continue
			}
		}
		rest := strings.TrimSpace(line[idx:])
		parts := strings.SplitN(rest, " ", 2)
		if len(parts) < 2 {
			continue
		}
		p := strings.TrimSpace(parts[1])
		if strings.HasSuffix(strings.ToLower(p), "typora.exe") {
			p = filepath.Dir(p)
		}
		p = filepath.Clean(p)
		if _, err := os.Stat(filepath.Join(p, "Typora.exe")); err == nil {
			return p
		}
	}
	return ""
}

func chooseTyporaDir() string {
	clearScreen()
	fmt.Printf("%s=================================%s\n", cCyanB, cReset)
	fmt.Printf("%s        Typora 激活脚本          %s\n", cMagenta, cReset)
	fmt.Printf("%s=================================%s\n", cCyanB, cReset)

	cache := readCache()
	if cache.Path != "" {
		fmt.Printf("%s✅ 检测到缓存路径: %s%s\n", cGreen, cache.Path, cReset)
		fmt.Printf("%s是否使用此路径？[Y/n]：%s", cCyan, cReset)
		use := strings.TrimSpace(strings.ToLower(readLine()))
		if use != "n" && use != "no" {
			fmt.Printf("%s✅ 已选择：%s%s\n", cGreenB, cache.Path, cReset)
			return cache.Path
		}
		fmt.Printf("%s已跳过缓存路径，正在尝试从注册表读取...%s\n", cYellow, cReset)
	}

	regPath := readRegPath()
	if regPath != "" {
		fmt.Printf("%s✅ 从注册表检测到路径: %s%s\n", cGreen, regPath, cReset)
		fmt.Printf("%s是否使用此路径？[Y/n]：%s", cCyan, cReset)
		use := strings.TrimSpace(strings.ToLower(readLine()))
		if use != "n" && use != "no" {
			fmt.Printf("%s✅ 已选择：%s%s\n", cGreenB, regPath, cReset)
			saveCache(cacheConfig{Path: regPath, MachineCode: cache.MachineCode, Email: cache.Email})
			return regPath
		}
		fmt.Printf("%s已跳过注册表路径，进入文件夹选择窗口...%s\n", cYellow, cReset)
	} else {
		fmt.Printf("%s未在注册表中找到 Typora，准备打开文件夹选择窗口...%s\n", cYellow, cReset)
	}

	selected, err := folderBrowserDialog()
	if err == nil && selected != "" {
		fmt.Printf("%s✅ 已选择：%s%s\n", cGreenB, selected, cReset)
		saveCache(cacheConfig{Path: selected, MachineCode: cache.MachineCode, Email: cache.Email})
		return selected
	}

	fmt.Printf("%s\n❌ 图形窗口不可用，切换手动输入%s\n", cRedB, cReset)
	return manualInputPath(cache)
}

func manualInputPath(cache cacheConfig) string {
	for {
		fmt.Printf("%s请输入 Typora 安装目录路径（例如 C:\\Program Files\\Typora）: %s", cCyan, cReset)
		input := strings.TrimSpace(readLine())
		if input == "" {
			fmt.Printf("%s路径不能为空，请重新输入！%s\n", cRed, cReset)
			continue
		}
		res := filepath.Clean(input)
		if _, err := os.Stat(filepath.Join(res, "Typora.exe")); err == nil {
			saveCache(cacheConfig{Path: res, MachineCode: cache.MachineCode, Email: cache.Email})
			return res
		}
		fmt.Printf("%s❌ 该路径下无效，请重新输入！%s\n", cRed, cReset)
	}
}

func folderBrowserDialog() (string, error) {
	psScript := `
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8;
$OutputEncoding = [System.Text.Encoding]::UTF8;
Add-Type -AssemblyName System.Windows.Forms;
$fbd=New-Object System.Windows.Forms.FolderBrowserDialog;
$fbd.Description='请选择 Typora 安装目录';
$fbd.ShowNewFolderButton=$false;
if($fbd.ShowDialog() -eq [System.Windows.Forms.DialogResult]::OK){
    Write-Output $fbd.SelectedPath
}
`
	cmd := exec.Command("powershell.exe", "-NoProfile", "-ExecutionPolicy", "Bypass", "-Command", psScript)
	cmd.Stdin = nil
	cmd.Stderr = nil
	cmd.SysProcAttr = &syscall.SysProcAttr{HideWindow: false}
	out, err := cmd.Output()
	if err != nil {
		return "", err
	}
	result := strings.TrimSpace(string(out))
	if result == "" {
		return "", fmt.Errorf("未选择路径")
	}
	return filepath.Clean(result), nil
}

// ========== Machine Code / Email Input ==========

func getMachineCodeAndEmail() (string, string) {
	cache := readCache()
	if cache.MachineCode != "" && cache.Email != "" {
		fmt.Printf("%s\n✅ 检测到缓存的激活信息:%s\n", cGreen, cReset)
		fmt.Printf("%s   机器码: %s%s\n", cGreen, cache.MachineCode, cReset)
		fmt.Printf("%s   邮箱: %s%s\n", cGreen, cache.Email, cReset)
		fmt.Printf("%s是否使用此信息？[Y/n]：%s", cCyan, cReset)
		use := strings.TrimSpace(strings.ToLower(readLine()))
		if use != "n" && use != "no" {
			fmt.Printf("%s✅ 已使用缓存的激活信息！%s\n", cGreenB, cReset)
			return cache.MachineCode, cache.Email
		}
		fmt.Printf("%s已跳过缓存的激活信息，进入手动输入...%s\n", cYellow, cReset)
	}

	var machineCode, email string
	for {
		fmt.Printf("%s\n请输入机器码: %s", cCyanB, cReset)
		machineCode = strings.TrimSpace(readLine())
		fmt.Printf("%s请输入邮箱: %s", cCyanB, cReset)
		email = strings.TrimSpace(readLine())

		if machineCode == "" {
			fmt.Printf("%s❌ 机器码不能为空，请重新输入！%s\n", cRed, cReset)
			continue
		}
		if email == "" {
			fmt.Printf("%s❌ 邮箱不能为空，请重新输入！%s\n", cRed, cReset)
			continue
		}
		break
	}

	saveCache(cacheConfig{
		Path:        cache.Path,
		MachineCode: machineCode,
		Email:       email,
	})
	return machineCode, email
}

// ========== Rollback ==========

func rollbackTypora(typoraPath string) {
	fmt.Printf("%s\n🔄 开始执行回滚还原...%s\n", cYellowB, cReset)

	resourcesPath := filepath.Join(typoraPath, "resources")
	asarPath := filepath.Join(resourcesPath, "app.asar")
	asarBakPath := filepath.Join(resourcesPath, "app.asar.bak")
	appDir := filepath.Join(resourcesPath, "app")
	appBakDir := filepath.Join(resourcesPath, "app.bak")
	typoraExe := filepath.Join(typoraPath, "Typora.exe")
	exeBakPath := typoraExe + ".bak"

	closeTyporaProcesses()
	time.Sleep(300 * time.Millisecond)

	// Restore original app.asar from backup
	if _, err := os.Stat(asarBakPath); err == nil {
		os.Remove(asarPath)
		os.Rename(asarBakPath, asarPath)
		fmt.Printf("%s✅ 已还原 app.asar%s\n", cGreen, cReset)
	}

	// Restore original Typora.exe from backup
	if _, err := os.Stat(exeBakPath); err == nil {
		os.Remove(typoraExe)
		os.Rename(exeBakPath, typoraExe)
		fmt.Printf("%s✅ 已还原 Typora.exe%s\n", cGreen, cReset)
	}

	// Clean up extracted app directory
	if _, err := os.Stat(appDir); err == nil {
		os.RemoveAll(appDir)
		fmt.Printf("%s✅ 已删除解包 app 目录%s\n", cGreen, cReset)
	}

	// Clean up backup directory
	if _, err := os.Stat(appBakDir); err == nil {
		os.RemoveAll(appBakDir)
	}

	deleteRegValue("HKCU\\Software\\Typora", "SLicense")
	deleteRegValue("HKCU\\Software\\Typora", "IDate")
	fmt.Printf("%s✅ 已清理授权信息%s\n", cGreen, cReset)

	fmt.Printf("%s\n🎉 回滚完成！已恢复为官方原版！%s\n", cGreenB, cReset)
	quit(0)
}

// ========== Code Injection ==========

func getInsertCode(enableHookDebug bool, atobMachineCode map[string]string, email, nowDateStr string) string {
	actEntity := map[string]string{
		"deviceId":    atobMachineCode["l"],
		"fingerprint": atobMachineCode["i"],
		"email":       email,
		"license":     "Cracked_By_DreamNya",
		"version":     atobMachineCode["v"],
		"date":        nowDateStr,
		"type":        "DreamNya",
	}
	actEntityJSON, _ := json.Marshal(actEntity)
	standardLicenseMsg := base64.StdEncoding.EncodeToString(actEntityJSON)
	actEntityJSONStr := string(actEntityJSON)
	enableDebugStr := "false"
	if enableHookDebug {
		enableDebugStr = "true"
	}

	return fmt.Sprintf(`
/** Hook破解开始 */
const electron = require("electron");
if (%s) {
    Object.defineProperty(electron.app, "quit", {
        value: function () {},
        writable: true,
        configurable: true,
    });
}
electron.app.on("browser-window-created", (_event, win) => {
    win.webContents.once("dom-ready", () => {
        if (%s) win.webContents.openDevTools({ mode: "detach" });
    });
});
const fsPathFrom = /resources[\\/]app[\\/]/i;
const fsPathTo = "resources\\app.bak\\";
const fsHook = {};
[
    "readFileSync","readFile","statSync","stat","Stats","StatsFs","open","openSync"
].forEach((property) => {
    fsHook[property] = fs[property];
    fs[property] = function (filePath, ...args) {
        if (typeof filePath == "string" && fsPathFrom.test(filePath)) {
            return fsHook[property].call(this, filePath.replace(fsPathFrom, fsPathTo), ...args);
        }
        return fsHook[property].call(this, filePath, ...args);
    };
});
const fsPromisesHook = {};
["readFile","open","stat"].forEach((property) => {
    fsPromisesHook[property] = fs.promises[property];
    fs.promises[property] = async function (filePath, ...args) {
        if (typeof filePath == "string" && fsPathFrom.test(filePath)) {
            return fsPromisesHook[property].call(this, filePath.replace(fsPathFrom, fsPathTo), ...args);
        }
        return fsPromisesHook[property].call(this, filePath, ...args);
    };
});
const crypto = require("crypto");
const originalPublicDecrypt = crypto.publicDecrypt;
crypto.publicDecrypt = function (key, buffer) {
    try {
        return originalPublicDecrypt.call(this, key, buffer);
    } catch (e) {
        return Buffer.from(JSON.stringify(%s));
    }
};
(function registerProtocolHandler() {
    try {
        electron.protocol.handle("https", async (request) => {
            if (request.url.includes('releases/windows_64.json')) {
                return new Response(JSON.stringify({ name: "typora", version: "0.0.0", releaseNoteLink: "", download: "", downloadCN: "", alternatives: {} }), { status: 200 });
            }
            if (request.url.includes('api/client/activate') || request.url.includes('api/client/renew')) {
                return new Response(JSON.stringify({
                    success: true, code: 0, retry: true, msg: "%s"
                }), { status: 200 });
            }
            return electron.net.fetch(request, { bypassCustomProtocolHandlers: true });
        });
    } catch (_) {
        electron.app.whenReady().then(() => {
            try {
                electron.protocol.handle("https", async (request) => {
                    if (request.url.includes('releases/windows_64.json')) {
                        return new Response(JSON.stringify({ name: "typora", version: "0.0.0", releaseNoteLink: "", download: "", downloadCN: "", alternatives: {} }), { status: 200 });
                    }
                    if (request.url.includes('api/client/activate') || request.url.includes('api/client/renew')) {
                        return new Response(JSON.stringify({
                            success: true, code: 0, retry: true, msg: "%s"
                        }), { status: 200 });
                    }
                    return electron.net.fetch(request, { bypassCustomProtocolHandlers: true });
                });
            } catch (_2) {}
        });
    }
})();
/** Hook破解结束 */
`, enableDebugStr, enableDebugStr, actEntityJSONStr, standardLicenseMsg, standardLicenseMsg)
}
