package system

import (
	"context"
	"errors"
	"fmt"
	"go/ast"
	"go/format"
	"go/parser"
	"go/token"
	"io"
	"os"
	"path/filepath"
	"strings"

	"kra/internal/biz/system"
	"kra/internal/conf"
	astUtils "kra/pkg/utils/ast"

	"gorm.io/gorm"
)

type SysAutoCodePackage struct {
	gorm.Model
	Desc        string `json:"desc" gorm:"comment:描述"`
	Label       string `json:"label" gorm:"comment:展示名"`
	Template    string `json:"template" gorm:"comment:模版"`
	PackageName string `json:"packageName" gorm:"comment:包名"`
	Module      string `json:"-" gorm:"comment:模块"`
}

func (SysAutoCodePackage) TableName() string { return "sys_auto_code_packages" }

type autoCodePackageRepo struct {
	db     *gorm.DB
	config *conf.AutoCodeConfig
}

func NewAutoCodePackageRepo(db *gorm.DB, config *conf.AutoCodeConfig) system.AutoCodePackageRepo {
	return &autoCodePackageRepo{db: db, config: config}
}

func (r *autoCodePackageRepo) Create(ctx context.Context, pkg *system.SysAutoCodePackage) error {
	entity := &SysAutoCodePackage{Model: gorm.Model{ID: pkg.ID}, Desc: pkg.Desc, Label: pkg.Label, Template: pkg.Template, PackageName: pkg.PackageName, Module: pkg.Module}
	if err := r.db.WithContext(ctx).Create(entity).Error; err != nil {
		return err
	}
	pkg.ID = entity.ID
	return nil
}

func (r *autoCodePackageRepo) Delete(ctx context.Context, id uint) error {
	return r.db.WithContext(ctx).Delete(&SysAutoCodePackage{}, id).Error
}

func (r *autoCodePackageRepo) DeleteByNames(ctx context.Context, names []string) error {
	if len(names) == 0 {
		return nil
	}
	return r.db.WithContext(ctx).Where("package_name IN ?", names).Delete(&SysAutoCodePackage{}).Error
}

func (r *autoCodePackageRepo) All(ctx context.Context) ([]system.SysAutoCodePackage, error) {
	var entities []SysAutoCodePackage
	if err := r.db.WithContext(ctx).Find(&entities).Error; err != nil {
		return nil, err
	}
	result := make([]system.SysAutoCodePackage, len(entities))
	for i, m := range entities {
		result[i] = system.SysAutoCodePackage{ID: m.ID, Desc: m.Desc, Label: m.Label, Template: m.Template, PackageName: m.PackageName, Module: m.Module}
	}
	return result, nil
}

func (r *autoCodePackageRepo) First(ctx context.Context, packageName, template string) (*system.SysAutoCodePackage, error) {
	var entity SysAutoCodePackage
	err := r.db.WithContext(ctx).Where("package_name = ? AND template = ?", packageName, template).First(&entity).Error
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, nil
		}
		return nil, err
	}
	return &system.SysAutoCodePackage{ID: entity.ID, Desc: entity.Desc, Label: entity.Label, Template: entity.Template, PackageName: entity.PackageName, Module: entity.Module}, nil
}

func (r *autoCodePackageRepo) FindByPackageName(ctx context.Context, packageName string) (*system.SysAutoCodePackage, error) {
	var entity SysAutoCodePackage
	err := r.db.WithContext(ctx).Where("package_name = ?", packageName).First(&entity).Error
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, nil
		}
		return nil, err
	}
	return &system.SysAutoCodePackage{ID: entity.ID, Desc: entity.Desc, Label: entity.Label, Template: entity.Template, PackageName: entity.PackageName, Module: entity.Module}, nil
}

func (r *autoCodePackageRepo) BatchCreate(ctx context.Context, pkgs []system.SysAutoCodePackage) error {
	if len(pkgs) == 0 {
		return nil
	}
	list := make([]SysAutoCodePackage, len(pkgs))
	for i, p := range pkgs {
		list[i] = SysAutoCodePackage{Model: gorm.Model{ID: p.ID}, Desc: p.Desc, Label: p.Label, Template: p.Template, PackageName: p.PackageName, Module: p.Module}
	}
	return r.db.WithContext(ctx).Create(&list).Error
}

func (r *autoCodePackageRepo) DeleteByIDs(ctx context.Context, ids []uint) error {
	if len(ids) == 0 {
		return nil
	}
	return r.db.WithContext(ctx).Delete(&SysAutoCodePackage{}, ids).Error
}

// Templates 获取模板文件映射
// 返回: dataList(模板内容), asts(AST注入), fileList(文件路径映射)
func (r *autoCodePackageRepo) Templates(ctx context.Context, entity *system.SysAutoCodePackage, info interface{}, isPackage bool) (map[string]string, map[string]system.Ast, map[string]string, error) {
	dataList := make(map[string]string)
	fileList := make(map[string]string)
	asts := make(map[string]system.Ast)

	templatePath := r.config.Root
	if templatePath == "" {
		templatePath = "resource"
	}

	// 处理服务端模板
	serverPath := filepath.Join(templatePath, entity.Template, "server")
	if _, err := os.Stat(serverPath); err == nil {
		if err := r.processKratosDDDServerDir(serverPath, entity, info, dataList, fileList, asts, isPackage); err != nil {
			return nil, nil, nil, fmt.Errorf("处理服务端模板失败: %w", err)
		}
	}

	// 处理前端模板
	webPath := filepath.Join(templatePath, entity.Template, "web")
	if _, err := os.Stat(webPath); err == nil {
		if err := r.processKratosDDDWebDir(webPath, entity, info, dataList, fileList, isPackage); err != nil {
			return nil, nil, nil, fmt.Errorf("处理前端模板失败: %w", err)
		}
	}

	return dataList, asts, fileList, nil
}

// processKratosDDDServerDir 处理 Kratos DDD 服务端目录
func (r *autoCodePackageRepo) processKratosDDDServerDir(serverPath string, entity *system.SysAutoCodePackage, info interface{}, dataList, fileList map[string]string, asts map[string]system.Ast, isPackage bool) error {
	for _, mapping := range system.KratosDDDServerMappings {
		dirPath := filepath.Join(serverPath, mapping.TemplateDir)
		if _, err := os.Stat(dirPath); os.IsNotExist(err) {
			continue
		}

		switch mapping.TemplateDir {
		case "biz", "data", "handler", "api", "service":
			if err := r.processKratosDDDLayerDir(dirPath, mapping, entity, info, dataList, fileList, asts, isPackage); err != nil {
				return err
			}
		case "router":
			if err := r.processKratosDDDRouterDir(dirPath, mapping, entity, info, dataList, fileList, asts, isPackage); err != nil {
				return err
			}
		case "model", "model/request":
			if err := r.processKratosDDDModelDir(dirPath, mapping, entity, info, dataList, fileList, asts, isPackage); err != nil {
				return err
			}
		case "types":
			if err := r.processServerTypesDir(dirPath, mapping, entity, info, dataList, fileList, isPackage); err != nil {
				return err
			}
		}
	}
	return nil
}

// processKratosDDDLayerDir 处理 biz/data/handler/service 层目录
func (r *autoCodePackageRepo) processKratosDDDLayerDir(dirPath string, mapping system.TemplateDirMapping, entity *system.SysAutoCodePackage, info interface{}, dataList, fileList map[string]string, asts map[string]system.Ast, isPackage bool) error {
	return filepath.Walk(dirPath, func(path string, fileInfo os.FileInfo, err error) error {
		if err != nil || fileInfo.IsDir() {
			return err
		}
		if !strings.HasSuffix(fileInfo.Name(), ".tpl") {
			return nil
		}

		content, err := os.ReadFile(path)
		if err != nil {
			return fmt.Errorf("读取模板文件失败 %s: %w", path, err)
		}

		// 计算目标路径
		targetDir := strings.ReplaceAll(mapping.TargetDir, "{package}", entity.PackageName)
		fileName := strings.TrimSuffix(fileInfo.Name(), ".tpl") + ".go"
		targetPath := filepath.Join(targetDir, fileName)

		dataList[path] = string(content)
		fileList[path] = targetPath

		// 添加 enter.go AST 注入
		if !isPackage {
			r.addKratosDDDEnterAst(mapping.TemplateDir, entity, asts)
			// 添加 Wire Provider AST 注入
			r.addKratosDDDWireProviderAst(mapping.TemplateDir, entity, info, asts)
		}

		return nil
	})
}

// processKratosDDDRouterDir 处理 router 层目录
func (r *autoCodePackageRepo) processKratosDDDRouterDir(dirPath string, mapping system.TemplateDirMapping, entity *system.SysAutoCodePackage, info interface{}, dataList, fileList map[string]string, asts map[string]system.Ast, isPackage bool) error {
	return filepath.Walk(dirPath, func(path string, fileInfo os.FileInfo, err error) error {
		if err != nil || fileInfo.IsDir() {
			return err
		}
		if !strings.HasSuffix(fileInfo.Name(), ".tpl") {
			return nil
		}

		content, err := os.ReadFile(path)
		if err != nil {
			return fmt.Errorf("读取模板文件失败 %s: %w", path, err)
		}

		targetDir := strings.ReplaceAll(mapping.TargetDir, "{package}", entity.PackageName)
		fileName := strings.TrimSuffix(fileInfo.Name(), ".tpl") + ".go"
		targetPath := filepath.Join(targetDir, fileName)

		dataList[path] = string(content)
		fileList[path] = targetPath

		// 添加 router enter.go 和 init AST 注入
		if !isPackage {
			r.addKratosDDDRouterEnterAst(entity, asts)
			r.addKratosDDDRouterInitAst(entity, asts)
		}

		return nil
	})
}

// processKratosDDDModelDir 处理 model 层目录
func (r *autoCodePackageRepo) processKratosDDDModelDir(dirPath string, mapping system.TemplateDirMapping, entity *system.SysAutoCodePackage, info interface{}, dataList, fileList map[string]string, asts map[string]system.Ast, isPackage bool) error {
	return filepath.Walk(dirPath, func(path string, fileInfo os.FileInfo, err error) error {
		if err != nil || fileInfo.IsDir() {
			return err
		}
		if !strings.HasSuffix(fileInfo.Name(), ".tpl") {
			return nil
		}

		content, err := os.ReadFile(path)
		if err != nil {
			return fmt.Errorf("读取模板文件失败 %s: %w", path, err)
		}

		targetDir := strings.ReplaceAll(mapping.TargetDir, "{package}", entity.PackageName)
		fileName := strings.TrimSuffix(fileInfo.Name(), ".tpl") + ".go"
		targetPath := filepath.Join(targetDir, fileName)

		dataList[path] = string(content)
		fileList[path] = targetPath

		// 添加 GORM Gen AST 注入（自动更新 cmd/gen/main.go）
		if !isPackage {
			r.addKratosDDDGormGenAst(entity, info, asts)
		}

		return nil
	})
}

// processServerTypesDir 处理 types 目录
func (r *autoCodePackageRepo) processServerTypesDir(dirPath string, mapping system.TemplateDirMapping, entity *system.SysAutoCodePackage, info interface{}, dataList, fileList map[string]string, isPackage bool) error {
	return filepath.Walk(dirPath, func(path string, fileInfo os.FileInfo, err error) error {
		if err != nil || fileInfo.IsDir() {
			return err
		}
		if !strings.HasSuffix(fileInfo.Name(), ".tpl") {
			return nil
		}

		content, err := os.ReadFile(path)
		if err != nil {
			return fmt.Errorf("读取模板文件失败 %s: %w", path, err)
		}

		targetDir := strings.ReplaceAll(mapping.TargetDir, "{package}", entity.PackageName)
		fileName := strings.TrimSuffix(fileInfo.Name(), ".tpl") + ".go"
		targetPath := filepath.Join(targetDir, fileName)

		dataList[path] = string(content)
		fileList[path] = targetPath

		return nil
	})
}

// processKratosDDDWebDir 处理 Kratos DDD 前端目录
func (r *autoCodePackageRepo) processKratosDDDWebDir(webPath string, entity *system.SysAutoCodePackage, info interface{}, dataList, fileList map[string]string, isPackage bool) error {
	for _, mapping := range system.KratosDDDWebMappings {
		dirPath := filepath.Join(webPath, mapping.TemplateDir)
		if _, err := os.Stat(dirPath); os.IsNotExist(err) {
			continue
		}

		switch mapping.TemplateDir {
		case "pages", "view":
			if err := r.processWebPagesDir(dirPath, mapping, entity, info, dataList, fileList, isPackage); err != nil {
				return err
			}
		case "services", "api":
			if err := r.processWebServicesDir(dirPath, mapping, entity, info, dataList, fileList, isPackage); err != nil {
				return err
			}
		case "types":
			if err := r.processWebTypesDir(dirPath, mapping, entity, info, dataList, fileList, isPackage); err != nil {
				return err
			}
		}
	}
	return nil
}

// processWebPagesDir 处理前端页面目录
func (r *autoCodePackageRepo) processWebPagesDir(dirPath string, mapping system.TemplateDirMapping, entity *system.SysAutoCodePackage, info interface{}, dataList, fileList map[string]string, isPackage bool) error {
	return filepath.Walk(dirPath, func(path string, fileInfo os.FileInfo, err error) error {
		if err != nil || fileInfo.IsDir() {
			return err
		}
		if !strings.HasSuffix(fileInfo.Name(), ".tpl") {
			return nil
		}

		content, err := os.ReadFile(path)
		if err != nil {
			return fmt.Errorf("读取模板文件失败 %s: %w", path, err)
		}

		// 获取实体名称用于路径替换
		entityName := entity.PackageName
		if autoInfo, ok := info.(*system.AutoCodeInfo); ok && autoInfo != nil {
			entityName = autoInfo.HumpPackageName
		}

		targetDir := strings.ReplaceAll(mapping.TargetDir, "{package}", entity.PackageName)
		targetDir = strings.ReplaceAll(targetDir, "{entity}", entityName)

		// 确定文件扩展名
		baseName := strings.TrimSuffix(fileInfo.Name(), ".tpl")
		var fileName string
		if strings.HasSuffix(baseName, ".tsx") || strings.HasSuffix(baseName, ".vue") {
			fileName = baseName
		} else {
			fileName = baseName + ".tsx"
		}
		targetPath := filepath.Join(targetDir, fileName)

		dataList[path] = string(content)
		fileList[path] = targetPath

		return nil
	})
}

// processWebServicesDir 处理前端服务目录
func (r *autoCodePackageRepo) processWebServicesDir(dirPath string, mapping system.TemplateDirMapping, entity *system.SysAutoCodePackage, info interface{}, dataList, fileList map[string]string, isPackage bool) error {
	return filepath.Walk(dirPath, func(path string, fileInfo os.FileInfo, err error) error {
		if err != nil || fileInfo.IsDir() {
			return err
		}
		if !strings.HasSuffix(fileInfo.Name(), ".tpl") {
			return nil
		}

		content, err := os.ReadFile(path)
		if err != nil {
			return fmt.Errorf("读取模板文件失败 %s: %w", path, err)
		}

		targetDir := mapping.TargetDir
		baseName := strings.TrimSuffix(fileInfo.Name(), ".tpl")
		var fileName string
		if strings.HasSuffix(baseName, ".ts") {
			fileName = baseName
		} else {
			fileName = baseName + ".ts"
		}
		targetPath := filepath.Join(targetDir, fileName)

		dataList[path] = string(content)
		fileList[path] = targetPath

		return nil
	})
}

// processWebTypesDir 处理前端类型目录
func (r *autoCodePackageRepo) processWebTypesDir(dirPath string, mapping system.TemplateDirMapping, entity *system.SysAutoCodePackage, info interface{}, dataList, fileList map[string]string, isPackage bool) error {
	return filepath.Walk(dirPath, func(path string, fileInfo os.FileInfo, err error) error {
		if err != nil || fileInfo.IsDir() {
			return err
		}
		if !strings.HasSuffix(fileInfo.Name(), ".tpl") {
			return nil
		}

		content, err := os.ReadFile(path)
		if err != nil {
			return fmt.Errorf("读取模板文件失败 %s: %w", path, err)
		}

		targetDir := strings.ReplaceAll(mapping.TargetDir, "{package}", entity.PackageName)
		baseName := strings.TrimSuffix(fileInfo.Name(), ".tpl")
		var fileName string
		if strings.HasSuffix(baseName, ".ts") || strings.HasSuffix(baseName, ".d.ts") {
			fileName = baseName
		} else {
			fileName = baseName + ".ts"
		}
		targetPath := filepath.Join(targetDir, fileName)

		dataList[path] = string(content)
		fileList[path] = targetPath

		return nil
	})
}

// addKratosDDDEnterAst 添加 enter.go AST 注入
func (r *autoCodePackageRepo) addKratosDDDEnterAst(layer string, entity *system.SysAutoCodePackage, asts map[string]system.Ast) {
	var enterPath string
	var astType string
	switch layer {
	case "biz":
		enterPath = "internal/biz/enter.go"
		astType = "PackageBizEnter"
	case "data":
		enterPath = "internal/data/enter.go"
		astType = "PackageDataEnter"
	case "handler", "api":
		enterPath = "internal/server/handler/enter.go"
		astType = "PackageApiEnter"
	case "service":
		enterPath = "internal/service/enter.go"
		astType = "PackageServiceEnter"
	default:
		return
	}

	key := fmt.Sprintf("%s=>%s", enterPath, astType)
	if _, exists := asts[key]; !exists {
		asts[key] = &KratosDDDEnterAst{
			Layer:       layer,
			PackageName: entity.PackageName,
			Type:        "enter",
			Path:        enterPath,
		}
	}
}

// addKratosDDDRouterEnterAst 添加 router enter.go AST 注入
func (r *autoCodePackageRepo) addKratosDDDRouterEnterAst(entity *system.SysAutoCodePackage, asts map[string]system.Ast) {
	enterPath := "internal/server/router/enter.go"
	astType := "PackageRouterEnter"
	key := fmt.Sprintf("%s=>%s", enterPath, astType)
	if _, exists := asts[key]; !exists {
		asts[key] = &KratosDDDRouterEnterAst{
			PackageName: entity.PackageName,
			Path:        enterPath,
		}
	}
}

// addKratosDDDRouterInitAst 添加 router 初始化 AST 注入
func (r *autoCodePackageRepo) addKratosDDDRouterInitAst(entity *system.SysAutoCodePackage, asts map[string]system.Ast) {
	initPath := "internal/server/http.go"
	astType := "PackageInitializeRouter"
	key := fmt.Sprintf("%s=>%s", initPath, astType)
	if _, exists := asts[key]; !exists {
		asts[key] = &KratosDDDRouterInitAst{
			PackageName: entity.PackageName,
			Path:        initPath,
		}
	}
}

// addKratosDDDGormMigrateAst 添加 GORM 迁移 AST 注入
func (r *autoCodePackageRepo) addKratosDDDGormMigrateAst(entity *system.SysAutoCodePackage, asts map[string]system.Ast) {
	migratePath := "internal/initialize/gorm.go"
	astType := "PackageInitializeGorm"
	key := fmt.Sprintf("%s=>%s", migratePath, astType)
	if _, exists := asts[key]; !exists {
		asts[key] = &KratosDDDGormMigrateAst{
			PackageName: entity.PackageName,
			Path:        migratePath,
		}
	}
}

// KratosDDDEnterAst enter.go AST 注入结构体
type KratosDDDEnterAst struct {
	Layer       string
	PackageName string
	Type        string
	Path        string // 文件路径
}

// Parse 解析文件
func (a *KratosDDDEnterAst) Parse(filename string, writer io.Writer) (*ast.File, error) {
	if filename == "" {
		filename = a.Path
	}
	if filename == "" {
		return nil, fmt.Errorf("文件路径为空")
	}
	fset := token.NewFileSet()
	file, err := parser.ParseFile(fset, filename, nil, parser.ParseComments)
	if err != nil {
		return nil, fmt.Errorf("解析文件失败 %s: %w", filename, err)
	}
	return file, nil
}

// Rollback 回滚注入
func (a *KratosDDDEnterAst) Rollback(file *ast.File) error {
	// 移除导入
	importPath := fmt.Sprintf("kra/internal/%s/%s", a.Layer, a.PackageName)
	astUtils.RemoveImport(file, importPath)

	// 移除结构体字段
	structName := a.getStructName()
	fieldName := strings.Title(a.PackageName)
	astUtils.RemoveStructField(file, structName, fieldName)

	return nil
}

// Injection 注入代码
func (a *KratosDDDEnterAst) Injection(file *ast.File) error {
	// 添加导入
	importPath := fmt.Sprintf("kra/internal/%s/%s", a.Layer, a.PackageName)
	astUtils.AddImport(file, importPath)

	// 添加结构体字段
	structName := a.getStructName()
	fieldName := strings.Title(a.PackageName)
	fieldType := fmt.Sprintf("%s.Group", a.PackageName)
	astUtils.AddStructField(file, structName, fieldName, fieldType)

	return nil
}

// Format 格式化输出
func (a *KratosDDDEnterAst) Format(filename string, writer io.Writer, file *ast.File) error {
	if filename == "" {
		filename = a.Path
	}
	fset := token.NewFileSet()
	return format.Node(writer, fset, file)
}

// getStructName 获取结构体名称
func (a *KratosDDDEnterAst) getStructName() string {
	switch a.Layer {
	case "biz":
		return "BizGroup"
	case "data":
		return "DataGroup"
	case "handler", "api":
		return "HandlerGroup"
	case "service":
		return "ServiceGroup"
	default:
		return "Group"
	}
}

// KratosDDDRouterEnterAst router enter.go AST 注入结构体
type KratosDDDRouterEnterAst struct {
	PackageName string
	Path        string // 文件路径
}

// Parse 解析文件
func (a *KratosDDDRouterEnterAst) Parse(filename string, writer io.Writer) (*ast.File, error) {
	if filename == "" {
		filename = a.Path
	}
	if filename == "" {
		return nil, fmt.Errorf("文件路径为空")
	}
	fset := token.NewFileSet()
	file, err := parser.ParseFile(fset, filename, nil, parser.ParseComments)
	if err != nil {
		return nil, fmt.Errorf("解析文件失败 %s: %w", filename, err)
	}
	return file, nil
}

// Rollback 回滚注入
func (a *KratosDDDRouterEnterAst) Rollback(file *ast.File) error {
	importPath := fmt.Sprintf("kra/internal/server/router/%s", a.PackageName)
	astUtils.RemoveImport(file, importPath)

	fieldName := strings.Title(a.PackageName)
	astUtils.RemoveStructField(file, "RouterGroup", fieldName)

	return nil
}

// Injection 注入代码
func (a *KratosDDDRouterEnterAst) Injection(file *ast.File) error {
	importPath := fmt.Sprintf("kra/internal/server/router/%s", a.PackageName)
	astUtils.AddImport(file, importPath)

	fieldName := strings.Title(a.PackageName)
	fieldType := fmt.Sprintf("%s.RouterGroup", a.PackageName)
	astUtils.AddStructField(file, "RouterGroup", fieldName, fieldType)

	return nil
}

// Format 格式化输出
func (a *KratosDDDRouterEnterAst) Format(filename string, writer io.Writer, file *ast.File) error {
	if filename == "" {
		filename = a.Path
	}
	fset := token.NewFileSet()
	return format.Node(writer, fset, file)
}

// KratosDDDRouterInitAst router 初始化 AST 注入结构体
type KratosDDDRouterInitAst struct {
	PackageName string
	Path        string // 文件路径
}

// Parse 解析文件
func (a *KratosDDDRouterInitAst) Parse(filename string, writer io.Writer) (*ast.File, error) {
	if filename == "" {
		filename = a.Path
	}
	if filename == "" {
		return nil, fmt.Errorf("文件路径为空")
	}
	fset := token.NewFileSet()
	file, err := parser.ParseFile(fset, filename, nil, parser.ParseComments)
	if err != nil {
		return nil, fmt.Errorf("解析文件失败 %s: %w", filename, err)
	}
	return file, nil
}

// Rollback 回滚注入
func (a *KratosDDDRouterInitAst) Rollback(file *ast.File) error {
	// 移除路由初始化调用
	funcName := fmt.Sprintf("Init%sRouter", strings.Title(a.PackageName))
	astUtils.RemoveFuncCall(file, "initRouter", funcName)
	return nil
}

// Injection 注入代码
func (a *KratosDDDRouterInitAst) Injection(file *ast.File) error {
	// 添加路由初始化调用
	funcName := fmt.Sprintf("Init%sRouter", strings.Title(a.PackageName))
	callExpr := fmt.Sprintf("router.%s.%s(group)", strings.Title(a.PackageName), funcName)
	astUtils.AddFuncCall(file, "initRouter", callExpr)
	return nil
}

// Format 格式化输出
func (a *KratosDDDRouterInitAst) Format(filename string, writer io.Writer, file *ast.File) error {
	if filename == "" {
		filename = a.Path
	}
	fset := token.NewFileSet()
	return format.Node(writer, fset, file)
}

// KratosDDDGormMigrateAst GORM 迁移 AST 注入结构体
type KratosDDDGormMigrateAst struct {
	PackageName string
	Path        string // 文件路径
}

// Parse 解析文件
func (a *KratosDDDGormMigrateAst) Parse(filename string, writer io.Writer) (*ast.File, error) {
	if filename == "" {
		filename = a.Path
	}
	if filename == "" {
		return nil, fmt.Errorf("文件路径为空")
	}
	fset := token.NewFileSet()
	file, err := parser.ParseFile(fset, filename, nil, parser.ParseComments)
	if err != nil {
		return nil, fmt.Errorf("解析文件失败 %s: %w", filename, err)
	}
	return file, nil
}

// Rollback 回滚注入
func (a *KratosDDDGormMigrateAst) Rollback(file *ast.File) error {
	// 移除模型导入
	importPath := fmt.Sprintf("kra/internal/data/model/%s", a.PackageName)
	astUtils.RemoveImport(file, importPath)

	// 移除 AutoMigrate 调用中的模型
	modelName := fmt.Sprintf("%s.%s", a.PackageName, strings.Title(a.PackageName))
	astUtils.RemoveAutoMigrateModel(file, modelName)

	return nil
}

// Injection 注入代码
func (a *KratosDDDGormMigrateAst) Injection(file *ast.File) error {
	// 添加模型导入
	importPath := fmt.Sprintf("kra/internal/data/model/%s", a.PackageName)
	astUtils.AddImport(file, importPath)

	// 添加 AutoMigrate 调用
	modelName := fmt.Sprintf("&%s.%s{}", a.PackageName, strings.Title(a.PackageName))
	astUtils.AddAutoMigrateModel(file, modelName)

	return nil
}

// Format 格式化输出
func (a *KratosDDDGormMigrateAst) Format(filename string, writer io.Writer, file *ast.File) error {
	if filename == "" {
		filename = a.Path
	}
	fset := token.NewFileSet()
	return format.Node(writer, fset, file)
}

// KratosDDDWireProviderAst Wire Provider AST 注入结构体
// 用于向各层的主 ProviderSet 中注入新包的 Provider
type KratosDDDWireProviderAst struct {
	Layer       string // 层名称: biz, data, service, handler, router
	PackageName string // 包名
	StructName  string // 结构体名
	Module      string // 模块名 (go.mod 中的 module)
	Path        string // 目标文件路径
}

// Parse 解析文件
func (a *KratosDDDWireProviderAst) Parse(filename string, writer io.Writer) (*ast.File, error) {
	if filename == "" {
		filename = a.Path
	}
	if filename == "" {
		return nil, fmt.Errorf("文件路径为空")
	}
	fset := token.NewFileSet()
	file, err := parser.ParseFile(fset, filename, nil, parser.ParseComments)
	if err != nil {
		return nil, fmt.Errorf("解析文件失败 %s: %w", filename, err)
	}
	return file, nil
}

// Rollback 回滚注入
func (a *KratosDDDWireProviderAst) Rollback(file *ast.File) error {
	// 移除导入
	importPath := a.getImportPath()
	astUtils.RemoveImport(file, importPath)

	// 移除 Provider
	providerName := a.getProviderName()
	return a.removeWireProvider(file, a.PackageName, providerName)
}

// Injection 注入代码
func (a *KratosDDDWireProviderAst) Injection(file *ast.File) error {
	// 添加导入
	importPath := a.getImportPath()
	astUtils.AddImport(file, importPath)

	// 添加 Provider
	providerName := a.getProviderName()
	return a.addWireProvider(file, a.PackageName, providerName)
}

// Format 格式化输出
func (a *KratosDDDWireProviderAst) Format(filename string, writer io.Writer, file *ast.File) error {
	if filename == "" {
		filename = a.Path
	}
	fset := token.NewFileSet()
	return format.Node(writer, fset, file)
}

// getImportPath 获取导入路径
func (a *KratosDDDWireProviderAst) getImportPath() string {
	module := a.Module
	if module == "" {
		module = "kra"
	}
	switch a.Layer {
	case "biz":
		return fmt.Sprintf("%s/internal/biz/%s", module, a.PackageName)
	case "data":
		return fmt.Sprintf("%s/internal/data/%s", module, a.PackageName)
	case "service":
		return fmt.Sprintf("%s/internal/service/%s", module, a.PackageName)
	case "handler", "api":
		return fmt.Sprintf("%s/internal/server/handler/%s", module, a.PackageName)
	case "router":
		return fmt.Sprintf("%s/internal/server/router/%s", module, a.PackageName)
	default:
		return ""
	}
}

// getProviderName 获取 Provider 名称
func (a *KratosDDDWireProviderAst) getProviderName() string {
	structName := a.StructName
	if structName == "" {
		structName = strings.Title(a.PackageName)
	}
	switch a.Layer {
	case "biz":
		return fmt.Sprintf("New%sUsecase", structName)
	case "data":
		return fmt.Sprintf("New%sRepo", structName)
	case "service":
		return fmt.Sprintf("New%sService", structName)
	case "handler", "api":
		return fmt.Sprintf("New%sHandler", structName)
	case "router":
		return fmt.Sprintf("New%sRouter", structName)
	default:
		return ""
	}
}

// addWireProvider 向 wire.NewSet 中添加带包名的 Provider
func (a *KratosDDDWireProviderAst) addWireProvider(file *ast.File, packageName, providerName string) error {
	var found bool
	ast.Inspect(file, func(node ast.Node) bool {
		genDecl, ok := node.(*ast.GenDecl)
		if !ok || genDecl.Tok != token.VAR {
			return true
		}

		for _, spec := range genDecl.Specs {
			valueSpec, ok := spec.(*ast.ValueSpec)
			if !ok {
				continue
			}

			for i, name := range valueSpec.Names {
				if name.Name != "ProviderSet" {
					continue
				}

				if i >= len(valueSpec.Values) {
					continue
				}

				callExpr, ok := valueSpec.Values[i].(*ast.CallExpr)
				if !ok {
					continue
				}

				selExpr, ok := callExpr.Fun.(*ast.SelectorExpr)
				if !ok {
					continue
				}

				ident, ok := selExpr.X.(*ast.Ident)
				if !ok || ident.Name != "wire" || selExpr.Sel.Name != "NewSet" {
					continue
				}

				// 构建完整的 Provider 名称
				fullProviderName := fmt.Sprintf("%s.%s", packageName, providerName)

				// 检查 Provider 是否已存在
				for _, arg := range callExpr.Args {
					if selArg, ok := arg.(*ast.SelectorExpr); ok {
						if pkgIdent, ok := selArg.X.(*ast.Ident); ok {
							existingName := fmt.Sprintf("%s.%s", pkgIdent.Name, selArg.Sel.Name)
							if existingName == fullProviderName {
								found = true
								return false // 已存在，不需要添加
							}
						}
					}
				}

				// 添加新的 Provider (package.ProviderName 格式)
				newArg := &ast.SelectorExpr{
					X:   &ast.Ident{Name: packageName},
					Sel: &ast.Ident{Name: providerName},
				}
				callExpr.Args = append(callExpr.Args, newArg)
				found = true
				return false
			}
		}
		return true
	})

	if !found {
		return fmt.Errorf("未找到 ProviderSet 变量或 wire.NewSet 调用")
	}
	return nil
}

// removeWireProvider 从 wire.NewSet 中移除带包名的 Provider
func (a *KratosDDDWireProviderAst) removeWireProvider(file *ast.File, packageName, providerName string) error {
	fullProviderName := fmt.Sprintf("%s.%s", packageName, providerName)

	ast.Inspect(file, func(node ast.Node) bool {
		genDecl, ok := node.(*ast.GenDecl)
		if !ok || genDecl.Tok != token.VAR {
			return true
		}

		for _, spec := range genDecl.Specs {
			valueSpec, ok := spec.(*ast.ValueSpec)
			if !ok {
				continue
			}

			for i, name := range valueSpec.Names {
				if name.Name != "ProviderSet" {
					continue
				}

				if i >= len(valueSpec.Values) {
					continue
				}

				callExpr, ok := valueSpec.Values[i].(*ast.CallExpr)
				if !ok {
					continue
				}

				selExpr, ok := callExpr.Fun.(*ast.SelectorExpr)
				if !ok {
					continue
				}

				ident, ok := selExpr.X.(*ast.Ident)
				if !ok || ident.Name != "wire" || selExpr.Sel.Name != "NewSet" {
					continue
				}

				// 移除指定的 Provider
				newArgs := make([]ast.Expr, 0, len(callExpr.Args))
				for _, arg := range callExpr.Args {
					if selArg, ok := arg.(*ast.SelectorExpr); ok {
						if pkgIdent, ok := selArg.X.(*ast.Ident); ok {
							existingName := fmt.Sprintf("%s.%s", pkgIdent.Name, selArg.Sel.Name)
							if existingName == fullProviderName {
								continue // 跳过要移除的 Provider
							}
						}
					}
					newArgs = append(newArgs, arg)
				}
				callExpr.Args = newArgs
				return false
			}
		}
		return true
	})
	return nil
}

// addKratosDDDWireProviderAst 添加 Wire Provider AST 注入
func (r *autoCodePackageRepo) addKratosDDDWireProviderAst(layer string, entity *system.SysAutoCodePackage, info interface{}, asts map[string]system.Ast) {
	var mainFilePath string
	var astType string

	switch layer {
	case "biz":
		mainFilePath = "internal/biz/biz.go"
		astType = "PackageBizWireProvider"
	case "data":
		mainFilePath = "internal/data/data.go"
		astType = "PackageDataWireProvider"
	case "service":
		mainFilePath = "internal/service/service.go"
		astType = "PackageServiceWireProvider"
	case "handler", "api":
		// Handler 层不需要注入到主文件，因为它使用 enter.go 的 Group 结构
		return
	case "router":
		// Router 层不需要注入到主文件，因为它使用 enter.go 的 RouterGroup 结构
		return
	default:
		return
	}

	// 获取结构体名
	structName := ""
	if autoInfo, ok := info.(*system.AutoCodeInfo); ok && autoInfo != nil {
		structName = autoInfo.StructName
	}
	if structName == "" {
		structName = strings.Title(entity.PackageName)
	}

	key := fmt.Sprintf("%s=>%s", mainFilePath, astType)
	if _, exists := asts[key]; !exists {
		asts[key] = &KratosDDDWireProviderAst{
			Layer:       layer,
			PackageName: entity.PackageName,
			StructName:  structName,
			Module:      entity.Module,
			Path:        mainFilePath,
		}
	}
}

// GetLayerMainFilePath 获取层的主文件路径
func GetLayerMainFilePath(layer string) string {
	switch layer {
	case "biz":
		return "internal/biz/biz.go"
	case "data":
		return "internal/data/data.go"
	case "service":
		return "internal/service/service.go"
	case "handler", "api":
		return "internal/server/handler/enter.go"
	case "router":
		return "internal/server/router/enter.go"
	default:
		return ""
	}
}

// KratosDDDGormGenAst GORM Gen AST 注入结构体
// 用于自动更新 cmd/gen/main.go 文件，添加新模型到 GORM Gen 配置
type KratosDDDGormGenAst struct {
	TableName   string // 数据库表名
	StructName  string // 结构体名
	PackageName string // 包名
	Path        string // 目标文件路径 (cmd/gen/main.go)
}

// Parse 解析文件
func (a *KratosDDDGormGenAst) Parse(filename string, writer io.Writer) (*ast.File, error) {
	if filename == "" {
		filename = a.Path
	}
	if filename == "" {
		filename = "cmd/gen/main.go"
	}
	fset := token.NewFileSet()
	file, err := parser.ParseFile(fset, filename, nil, parser.ParseComments)
	if err != nil {
		return nil, fmt.Errorf("解析文件失败 %s: %w", filename, err)
	}
	return file, nil
}

// Rollback 回滚注入
func (a *KratosDDDGormGenAst) Rollback(file *ast.File) error {
	// 从 g.ApplyBasic 调用中移除模型
	astUtils.RemoveGormGenModel(file, a.TableName)
	return nil
}

// Injection 注入代码
func (a *KratosDDDGormGenAst) Injection(file *ast.File) error {
	// 检查模型是否已存在
	if astUtils.CheckGormGenModelExists(file, a.TableName) {
		return nil // 已存在，不需要添加
	}
	// 向 g.ApplyBasic 调用中添加新模型
	astUtils.AddGormGenModel(file, a.TableName)
	return nil
}

// Format 格式化输出
func (a *KratosDDDGormGenAst) Format(filename string, writer io.Writer, file *ast.File) error {
	if filename == "" {
		filename = a.Path
	}
	fset := token.NewFileSet()
	return format.Node(writer, fset, file)
}

// addKratosDDDGormGenAst 添加 GORM Gen AST 注入
func (r *autoCodePackageRepo) addKratosDDDGormGenAst(entity *system.SysAutoCodePackage, info interface{}, asts map[string]system.Ast) {
	genPath := "cmd/gen/main.go"
	astType := "PackageGormGen"
	key := fmt.Sprintf("%s=>%s", genPath, astType)

	if _, exists := asts[key]; exists {
		return
	}

	// 获取表名和结构体名
	tableName := ""
	structName := ""
	if autoInfo, ok := info.(*system.AutoCodeInfo); ok && autoInfo != nil {
		tableName = autoInfo.TableName
		structName = autoInfo.StructName
	}
	if tableName == "" {
		tableName = entity.PackageName
	}
	if structName == "" {
		structName = strings.Title(entity.PackageName)
	}

	asts[key] = &KratosDDDGormGenAst{
		TableName:   tableName,
		StructName:  structName,
		PackageName: entity.PackageName,
		Path:        genPath,
	}
}
