package main

import (
	"encoding/json"
	"fmt"
	"os"
	"path/filepath"
	"strings"

	"github.com/spf13/cobra"
	"gopkg.in/yaml.v3"
)

var (
	// Generate command flags
	interactive  bool
	preview      bool
	dbName       string
	tableName    string
	packageName  string
	structName   string
	desc         string
	noWeb        bool
	noServer     bool
	onlyTemplate bool
	isAdd        bool
	isTree       bool
	treeJson     string
)

// generateCmd represents the generate command
var generateCmd = &cobra.Command{
	Use:   "generate",
	Short: "生成代码",
	Long: `根据配置生成 Kratos DDD 架构的后端代码和 React 前端代码。

支持三种方式:
  1. 配置文件方式: 使用 -c 指定 YAML/JSON 配置文件
  2. 命令行参数方式: 使用各种参数直接指定配置
  3. 交互模式: 使用 -i 进入交互式配置

使用示例:
  # 从配置文件生成
  kra-gen generate -c autocode.yaml

  # 使用命令行参数
  kra-gen generate --db mysql --table users --package example --struct User

  # 交互模式
  kra-gen generate -i

  # 预览模式（不写入文件）
  kra-gen generate -c autocode.yaml -p

  # 仅生成模板（不注入代码）
  kra-gen generate -c autocode.yaml --only-template

  # 树形结构数据
  kra-gen generate -c autocode.yaml --tree --tree-json name`,
	Run: runGenerate,
}

func init() {
	// Generate command specific flags
	generateCmd.Flags().BoolVarP(&interactive, "interactive", "i", false, "交互模式")
	generateCmd.Flags().BoolVarP(&preview, "preview", "p", false, "预览模式（不写入文件）")
	generateCmd.Flags().StringVar(&dbName, "db", "", "数据库连接名")
	generateCmd.Flags().StringVar(&tableName, "table", "", "表名")
	generateCmd.Flags().StringVar(&packageName, "package", "", "包名")
	generateCmd.Flags().StringVar(&structName, "struct", "", "结构体名")
	generateCmd.Flags().StringVar(&desc, "desc", "", "描述")
	generateCmd.Flags().BoolVar(&noWeb, "no-web", false, "不生成前端代码")
	generateCmd.Flags().BoolVar(&noServer, "no-server", false, "不生成后端代码")
	generateCmd.Flags().BoolVar(&onlyTemplate, "only-template", false, "仅生成模板（不注入代码到现有文件）")
	generateCmd.Flags().BoolVar(&isAdd, "add", false, "追加模式（不覆盖已有文件）")
	generateCmd.Flags().BoolVar(&isTree, "tree", false, "树形结构数据")
	generateCmd.Flags().StringVar(&treeJson, "tree-json", "", "树形结构展示字段")
}

// AutoCodeConfig represents the configuration for code generation
type AutoCodeConfig struct {
	Package      string          `json:"package" yaml:"package"`
	StructName   string          `json:"structName" yaml:"structName"`
	TableName    string          `json:"tableName" yaml:"tableName"`
	Description  string          `json:"description" yaml:"description"`
	BusinessDB   string          `json:"businessDB" yaml:"businessDB"`
	Abbreviation string          `json:"abbreviation" yaml:"abbreviation"`
	Options      AutoCodeOptions `json:"options" yaml:"options"`
	Fields       []AutoCodeField `json:"fields" yaml:"fields"`
}

// AutoCodeOptions represents generation options
type AutoCodeOptions struct {
	GvaModel            bool   `json:"gvaModel" yaml:"gvaModel"`                       // 使用 KRA_MODEL (包含 ID, CreatedAt, UpdatedAt, DeletedAt)
	AutoMigrate         bool   `json:"autoMigrate" yaml:"autoMigrate"`                 // 自动迁移数据库表结构
	AutoCreateResource  bool   `json:"autoCreateResource" yaml:"autoCreateResource"`   // 自动创建资源标识
	AutoCreateApiToSql  bool   `json:"autoCreateApiToSql" yaml:"autoCreateApiToSql"`   // 自动创建 API 记录
	AutoCreateMenuToSql bool   `json:"autoCreateMenuToSql" yaml:"autoCreateMenuToSql"` // 自动创建菜单记录
	AutoCreateBtnAuth   bool   `json:"autoCreateBtnAuth" yaml:"autoCreateBtnAuth"`     // 自动创建按钮权限
	OnlyTemplate        bool   `json:"onlyTemplate" yaml:"onlyTemplate"`               // 仅生成模板（不注入代码）
	IsTree              bool   `json:"isTree" yaml:"isTree"`                           // 树形结构
	TreeJson            string `json:"treeJson" yaml:"treeJson"`                       // 树形结构展示字段
	IsAdd               bool   `json:"isAdd" yaml:"isAdd"`                             // 追加模式（不覆盖已有文件）
	GenerateWeb         bool   `json:"generateWeb" yaml:"generateWeb"`                 // 生成前端代码
	GenerateServer      bool   `json:"generateServer" yaml:"generateServer"`           // 生成后端代码
}

// DataSource 数据源配置
type DataSource struct {
	DBName       string `json:"dbName" yaml:"dbName"`
	Table        string `json:"table" yaml:"table"`
	Label        string `json:"label" yaml:"label"`
	Value        string `json:"value" yaml:"value"`
	Association  int    `json:"association" yaml:"association"` // 关联关系 1 一对一 2 一对多
	HasDeletedAt bool   `json:"hasDeletedAt" yaml:"hasDeletedAt"`
}

// AutoCodeField represents a field configuration
type AutoCodeField struct {
	FieldName       string      `json:"fieldName" yaml:"fieldName"`
	FieldDesc       string      `json:"fieldDesc" yaml:"fieldDesc"`
	FieldType       string      `json:"fieldType" yaml:"fieldType"`
	FieldJson       string      `json:"fieldJson" yaml:"fieldJson"`
	ColumnName      string      `json:"columnName" yaml:"columnName"`
	DataTypeLong    string      `json:"dataTypeLong" yaml:"dataTypeLong"`
	Form            bool        `json:"form" yaml:"form"`
	Table           bool        `json:"table" yaml:"table"`
	Desc            bool        `json:"desc" yaml:"desc"`   // 是否前端详情
	Excel           bool        `json:"excel" yaml:"excel"` // 是否导入/导出
	Require         bool        `json:"require" yaml:"require"`
	DefaultValue    string      `json:"defaultValue" yaml:"defaultValue"` // 默认值
	ErrorText       string      `json:"errorText" yaml:"errorText"`       // 校验失败文字
	Clearable       bool        `json:"clearable" yaml:"clearable"`       // 是否可清空
	Sort            bool        `json:"sort" yaml:"sort"`                 // 是否增加排序
	FieldSearchType string      `json:"fieldSearchType" yaml:"fieldSearchType"`
	FieldSearchHide bool        `json:"fieldSearchHide" yaml:"fieldSearchHide"` // 是否隐藏查询条件
	DictType        string      `json:"dictType" yaml:"dictType"`
	DataSource      *DataSource `json:"dataSource" yaml:"dataSource"`         // 数据源
	FieldIndexType  string      `json:"fieldIndexType" yaml:"fieldIndexType"` // 索引类型
	PrimaryKey      bool        `json:"primaryKey" yaml:"primaryKey"`         // 是否主键
}

func runGenerate(cmd *cobra.Command, args []string) {
	var config *AutoCodeConfig
	var err error

	// Determine configuration source
	if configFile != "" {
		config, err = loadConfigFile(configFile)
		if err != nil {
			fmt.Fprintf(os.Stderr, "加载配置文件失败: %v\n", err)
			os.Exit(1)
		}
	} else if interactive {
		config, err = runInteractiveMode()
		if err != nil {
			fmt.Fprintf(os.Stderr, "交互模式错误: %v\n", err)
			os.Exit(1)
		}
	} else if hasRequiredFlags() {
		config = buildConfigFromFlags()
	} else {
		fmt.Println("请指定配置文件 (-c) 或使用交互模式 (-i) 或提供必要参数")
		fmt.Println("使用 'kra-gen generate --help' 查看帮助")
		os.Exit(1)
	}

	// Apply command line overrides
	applyFlagOverrides(config)

	// Validate configuration
	if err := validateConfig(config); err != nil {
		fmt.Fprintf(os.Stderr, "配置验证失败: %v\n", err)
		os.Exit(1)
	}

	// Execute generation
	if preview {
		if err := executePreview(config); err != nil {
			fmt.Fprintf(os.Stderr, "预览失败: %v\n", err)
			os.Exit(1)
		}
	} else {
		if err := executeGenerate(config); err != nil {
			fmt.Fprintf(os.Stderr, "生成失败: %v\n", err)
			os.Exit(1)
		}
	}
}

// loadConfigFile loads configuration from a YAML or JSON file
func loadConfigFile(path string) (*AutoCodeConfig, error) {
	data, err := os.ReadFile(path)
	if err != nil {
		return nil, fmt.Errorf("读取配置文件失败: %w", err)
	}

	config := &AutoCodeConfig{}
	ext := strings.ToLower(filepath.Ext(path))

	switch ext {
	case ".yaml", ".yml":
		if err := yaml.Unmarshal(data, config); err != nil {
			return nil, fmt.Errorf("解析 YAML 配置失败: %w", err)
		}
	case ".json":
		if err := json.Unmarshal(data, config); err != nil {
			return nil, fmt.Errorf("解析 JSON 配置失败: %w", err)
		}
	default:
		return nil, fmt.Errorf("不支持的配置文件格式: %s", ext)
	}

	return config, nil
}

// hasRequiredFlags checks if required command line flags are provided
func hasRequiredFlags() bool {
	return tableName != "" && packageName != "" && structName != ""
}

// buildConfigFromFlags builds configuration from command line flags
func buildConfigFromFlags() *AutoCodeConfig {
	abbreviation := strings.ToLower(structName)
	if len(abbreviation) > 0 {
		abbreviation = strings.ToLower(string(structName[0])) + structName[1:]
	}

	return &AutoCodeConfig{
		Package:      packageName,
		StructName:   structName,
		TableName:    tableName,
		Description:  desc,
		BusinessDB:   dbName,
		Abbreviation: abbreviation,
		Options: AutoCodeOptions{
			GvaModel:            true,
			AutoMigrate:         true,
			AutoCreateResource:  false,
			AutoCreateApiToSql:  true,
			AutoCreateMenuToSql: true,
			AutoCreateBtnAuth:   true,
			OnlyTemplate:        false,
			IsTree:              false,
			TreeJson:            "",
			IsAdd:               false,
			GenerateWeb:         !noWeb,
			GenerateServer:      !noServer,
		},
	}
}

// applyFlagOverrides applies command line flag overrides to the configuration
func applyFlagOverrides(config *AutoCodeConfig) {
	if noWeb {
		config.Options.GenerateWeb = false
	}
	if noServer {
		config.Options.GenerateServer = false
	}
	if onlyTemplate {
		config.Options.OnlyTemplate = true
	}
	if isAdd {
		config.Options.IsAdd = true
	}
	if isTree {
		config.Options.IsTree = true
	}
	if treeJson != "" {
		config.Options.TreeJson = treeJson
	}
}

// validateConfig validates the configuration
func validateConfig(config *AutoCodeConfig) error {
	if config.Package == "" {
		return fmt.Errorf("包名不能为空")
	}
	if config.StructName == "" {
		return fmt.Errorf("结构体名不能为空")
	}
	if config.TableName == "" {
		return fmt.Errorf("表名不能为空")
	}
	return nil
}

// executePreview executes preview mode
func executePreview(config *AutoCodeConfig) error {
	fmt.Println("========================================")
	fmt.Println("代码预览模式")
	fmt.Println("========================================")
	fmt.Printf("包名: %s\n", config.Package)
	fmt.Printf("结构体: %s\n", config.StructName)
	fmt.Printf("表名: %s\n", config.TableName)
	fmt.Printf("描述: %s\n", config.Description)
	fmt.Printf("数据库: %s\n", config.BusinessDB)
	fmt.Println("----------------------------------------")

	// 显示生成选项
	fmt.Println("生成选项:")
	fmt.Printf("  使用 KRA_MODEL: %s\n", boolToStr(config.Options.GvaModel))
	fmt.Printf("  自动迁移: %s\n", boolToStr(config.Options.AutoMigrate))
	fmt.Printf("  生成后端: %s\n", boolToStr(config.Options.GenerateServer))
	fmt.Printf("  生成前端: %s\n", boolToStr(config.Options.GenerateWeb))
	fmt.Printf("  仅生成模板: %s\n", boolToStr(config.Options.OnlyTemplate))
	fmt.Printf("  追加模式: %s\n", boolToStr(config.Options.IsAdd))
	if !config.Options.OnlyTemplate {
		fmt.Printf("  创建 API 记录: %s\n", boolToStr(config.Options.AutoCreateApiToSql))
		fmt.Printf("  创建菜单记录: %s\n", boolToStr(config.Options.AutoCreateMenuToSql))
		fmt.Printf("  创建按钮权限: %s\n", boolToStr(config.Options.AutoCreateBtnAuth))
		fmt.Printf("  创建资源标识: %s\n", boolToStr(config.Options.AutoCreateResource))
	}
	if config.Options.IsTree {
		fmt.Printf("  树形结构: 是 (展示字段: %s)\n", config.Options.TreeJson)
	}
	fmt.Println("----------------------------------------")
	fmt.Println("将生成以下文件:")
	fmt.Println()

	workDir := getWorkingDir()

	if config.Options.GenerateServer {
		fmt.Println("后端文件:")
		fmt.Printf("  - %s/internal/biz/%s/%s.go\n", workDir, config.Package, strings.ToLower(config.StructName))
		fmt.Printf("  - %s/internal/data/%s/%s.go\n", workDir, config.Package, strings.ToLower(config.StructName))
		fmt.Printf("  - %s/internal/data/model/%s/%s.go\n", workDir, config.Package, strings.ToLower(config.StructName))
		fmt.Printf("  - %s/internal/service/%s/%s.go\n", workDir, config.Package, strings.ToLower(config.StructName))
		fmt.Printf("  - %s/internal/service/types/%s/request/%s.go\n", workDir, config.Package, strings.ToLower(config.StructName))
		fmt.Printf("  - %s/internal/server/handler/%s/%s.go\n", workDir, config.Package, strings.ToLower(config.StructName))
		fmt.Printf("  - %s/internal/server/router/%s/%s.go\n", workDir, config.Package, strings.ToLower(config.StructName))
	}

	if config.Options.GenerateWeb {
		fmt.Println()
		fmt.Println("前端文件:")
		fmt.Printf("  - %s/web/src/pages/%s/%s/index.tsx\n", workDir, config.Package, strings.ToLower(config.StructName))
		fmt.Printf("  - %s/web/src/pages/%s/%s/form.tsx\n", workDir, config.Package, strings.ToLower(config.StructName))
		fmt.Printf("  - %s/web/src/pages/%s/%s/detail.tsx\n", workDir, config.Package, strings.ToLower(config.StructName))
		fmt.Printf("  - %s/web/src/services/kratos/%s.ts\n", workDir, config.Package)
		fmt.Printf("  - %s/web/src/types/%s/%s.d.ts\n", workDir, config.Package, strings.ToLower(config.StructName))
	}

	fmt.Println()
	fmt.Println("字段配置:")
	if len(config.Fields) == 0 {
		fmt.Println("  (未配置字段，将从数据库表结构读取)")
	} else {
		for _, field := range config.Fields {
			searchInfo := ""
			if field.FieldSearchType != "" {
				searchInfo = fmt.Sprintf(" [搜索:%s]", field.FieldSearchType)
			}
			dictInfo := ""
			if field.DictType != "" {
				dictInfo = fmt.Sprintf(" [字典:%s]", field.DictType)
			}
			fmt.Printf("  - %s (%s): %s%s%s\n", field.FieldName, field.FieldType, field.FieldDesc, searchInfo, dictInfo)
		}
	}

	fmt.Println()
	fmt.Println("========================================")
	fmt.Println("预览完成，未写入任何文件")
	fmt.Println("========================================")

	return nil
}

// boolToStr 将布尔值转换为是/否字符串
func boolToStr(b bool) string {
	if b {
		return "是"
	}
	return "否"
}

// executeGenerate executes the actual code generation
func executeGenerate(config *AutoCodeConfig) error {
	fmt.Println("========================================")
	fmt.Println("开始生成代码...")
	fmt.Println("========================================")
	fmt.Printf("包名: %s\n", config.Package)
	fmt.Printf("结构体: %s\n", config.StructName)
	fmt.Printf("表名: %s\n", config.TableName)
	fmt.Println("----------------------------------------")

	// TODO: 实现实际的代码生成逻辑
	// 这里需要调用 AutoCodeTemplateUsecase 的 Create 方法
	// 由于 CLI 工具需要独立运行，需要初始化数据库连接和依赖

	fmt.Println()
	fmt.Println("注意: 完整的代码生成功能需要连接数据库。")
	fmt.Println("请使用 Web 界面进行代码生成，或确保配置文件包含数据库连接信息。")
	fmt.Println()
	fmt.Println("========================================")
	fmt.Println("代码生成完成!")
	fmt.Println("========================================")

	return nil
}

// runInteractiveMode runs the interactive configuration mode
func runInteractiveMode() (*AutoCodeConfig, error) {
	// 使用新的交互模式实现，支持数据库/表选择
	return runInteractiveModeWithDB()
}
