package main

import (
	"bytes"
	"fmt"
	"os"
	"path/filepath"
	"strings"
	"text/template"

	"github.com/fatih/color"
	"github.com/spf13/cobra"
	"kra/pkg/utils/autocode"
)

// previewCmd represents the preview command
var previewCmd = &cobra.Command{
	Use:   "preview",
	Short: "预览生成的代码",
	Long: `预览将要生成的代码，不写入任何文件。

这是 'generate -p' 的快捷方式。

使用示例:
  # 从配置文件预览
  kra-gen preview -c autocode.yaml

  # 使用命令行参数预览
  kra-gen preview --table users --package example --struct User
  
  # 预览时显示完整代码内容
  kra-gen preview -c autocode.yaml --full
  
  # 预览时不使用语法高亮
  kra-gen preview -c autocode.yaml --full --no-color`,
	Run: runPreview,
}

var (
	// Preview specific flags
	fullPreview bool
	noColor     bool
)

func init() {
	// Preview command specific flags (same as generate)
	previewCmd.Flags().StringVar(&dbName, "db", "", "数据库连接名")
	previewCmd.Flags().StringVar(&tableName, "table", "", "表名")
	previewCmd.Flags().StringVar(&packageName, "package", "", "包名")
	previewCmd.Flags().StringVar(&structName, "struct", "", "结构体名")
	previewCmd.Flags().StringVar(&desc, "desc", "", "描述")
	previewCmd.Flags().BoolVar(&noWeb, "no-web", false, "不生成前端代码")
	previewCmd.Flags().BoolVar(&noServer, "no-server", false, "不生成后端代码")
	previewCmd.Flags().BoolVar(&fullPreview, "full", false, "显示完整代码内容")
	previewCmd.Flags().BoolVar(&noColor, "no-color", false, "不使用语法高亮")
}

func runPreview(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 hasRequiredFlags() {
		config = buildConfigFromFlags()
	} else {
		fmt.Println("请指定配置文件 (-c) 或提供必要参数 (--table, --package, --struct)")
		fmt.Println("使用 'kra-gen preview --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 preview
	if fullPreview {
		if err := executeFullPreview(config); err != nil {
			fmt.Fprintf(os.Stderr, "预览失败: %v\n", err)
			os.Exit(1)
		}
	} else {
		if err := executePreview(config); err != nil {
			fmt.Fprintf(os.Stderr, "预览失败: %v\n", err)
			os.Exit(1)
		}
	}
}

// TemplateInfo 模板信息
type TemplateInfo struct {
	Name       string // 模板名称
	Path       string // 模板路径
	OutputPath string // 输出路径
	Type       string // 类型: server/web
	Layer      string // 层级: biz/data/handler/service/router/pages/services/types
}

// getTemplateList 获取模板列表
func getTemplateList(config *AutoCodeConfig) []TemplateInfo {
	var templates []TemplateInfo
	workDir := getWorkingDir()
	pkg := config.Package
	structLower := strings.ToLower(config.StructName)

	if config.Options.GenerateServer {
		// 后端模板
		templates = append(templates, []TemplateInfo{
			{
				Name:       "Biz Layer",
				Path:       "server/biz/biz.go.tpl",
				OutputPath: filepath.Join(workDir, "internal/biz", pkg, structLower+".go"),
				Type:       "server",
				Layer:      "biz",
			},
			{
				Name:       "Biz Enter",
				Path:       "server/biz/enter.go.tpl",
				OutputPath: filepath.Join(workDir, "internal/biz", pkg, "enter.go"),
				Type:       "server",
				Layer:      "biz",
			},
			{
				Name:       "Data Layer",
				Path:       "server/data/data.go.tpl",
				OutputPath: filepath.Join(workDir, "internal/data", pkg, structLower+".go"),
				Type:       "server",
				Layer:      "data",
			},
			{
				Name:       "Data Enter",
				Path:       "server/data/enter.go.tpl",
				OutputPath: filepath.Join(workDir, "internal/data", pkg, "enter.go"),
				Type:       "server",
				Layer:      "data",
			},
			{
				Name:       "Data Model",
				Path:       "server/data/model.go.tpl",
				OutputPath: filepath.Join(workDir, "internal/data/model", pkg, structLower+".go"),
				Type:       "server",
				Layer:      "model",
			},
			{
				Name:       "Handler Layer",
				Path:       "server/handler/handler.go.tpl",
				OutputPath: filepath.Join(workDir, "internal/server/handler", pkg, structLower+".go"),
				Type:       "server",
				Layer:      "handler",
			},
			{
				Name:       "Handler Enter",
				Path:       "server/handler/enter.go.tpl",
				OutputPath: filepath.Join(workDir, "internal/server/handler", pkg, "enter.go"),
				Type:       "server",
				Layer:      "handler",
			},
			{
				Name:       "Service Layer",
				Path:       "server/service/service.go.tpl",
				OutputPath: filepath.Join(workDir, "internal/service", pkg, structLower+".go"),
				Type:       "server",
				Layer:      "service",
			},
			{
				Name:       "Service Enter",
				Path:       "server/service/enter.go.tpl",
				OutputPath: filepath.Join(workDir, "internal/service", pkg, "enter.go"),
				Type:       "server",
				Layer:      "service",
			},
			{
				Name:       "Request Types",
				Path:       "server/types/request.go.tpl",
				OutputPath: filepath.Join(workDir, "internal/service/types", pkg, "request", structLower+".go"),
				Type:       "server",
				Layer:      "types",
			},
			{
				Name:       "Router Layer",
				Path:       "server/router/router.go.tpl",
				OutputPath: filepath.Join(workDir, "internal/server/router", pkg, structLower+".go"),
				Type:       "server",
				Layer:      "router",
			},
			{
				Name:       "Router Enter",
				Path:       "server/router/enter.go.tpl",
				OutputPath: filepath.Join(workDir, "internal/server/router", pkg, "enter.go"),
				Type:       "server",
				Layer:      "router",
			},
		}...)
	}

	if config.Options.GenerateWeb {
		// 前端模板
		templates = append(templates, []TemplateInfo{
			{
				Name:       "React Page",
				Path:       "web/pages/index.tsx.tpl",
				OutputPath: filepath.Join(workDir, "web/src/pages", pkg, structLower, "index.tsx"),
				Type:       "web",
				Layer:      "pages",
			},
			{
				Name:       "React Form",
				Path:       "web/pages/form.tsx.tpl",
				OutputPath: filepath.Join(workDir, "web/src/pages", pkg, structLower, "form.tsx"),
				Type:       "web",
				Layer:      "pages",
			},
			{
				Name:       "React Detail",
				Path:       "web/pages/detail.tsx.tpl",
				OutputPath: filepath.Join(workDir, "web/src/pages", pkg, structLower, "detail.tsx"),
				Type:       "web",
				Layer:      "pages",
			},
			{
				Name:       "API Service",
				Path:       "web/services/api.ts.tpl",
				OutputPath: filepath.Join(workDir, "web/src/services/kratos", pkg+".ts"),
				Type:       "web",
				Layer:      "services",
			},
			{
				Name:       "TypeScript Types",
				Path:       "web/types/types.d.ts.tpl",
				OutputPath: filepath.Join(workDir, "web/src/types", pkg, structLower+".d.ts"),
				Type:       "web",
				Layer:      "types",
			},
		}...)
	}

	return templates
}

// buildTemplateData 构建模板数据
func buildTemplateData(config *AutoCodeConfig) map[string]interface{} {
	// 转换字段
	fields := make([]autocode.AutoCodeField, len(config.Fields))
	for i, f := range config.Fields {
		var ds *autocode.DataSource
		if f.DataSource != nil {
			ds = &autocode.DataSource{
				DBName:       f.DataSource.DBName,
				Table:        f.DataSource.Table,
				Label:        f.DataSource.Label,
				Value:        f.DataSource.Value,
				Association:  f.DataSource.Association,
				HasDeletedAt: f.DataSource.HasDeletedAt,
			}
		}
		fields[i] = autocode.AutoCodeField{
			FieldName:       f.FieldName,
			FieldDesc:       f.FieldDesc,
			FieldType:       f.FieldType,
			FieldJson:       f.FieldJson,
			DataTypeLong:    f.DataTypeLong,
			ColumnName:      f.ColumnName,
			FieldSearchType: f.FieldSearchType,
			FieldSearchHide: f.FieldSearchHide,
			DictType:        f.DictType,
			Form:            f.Form,
			Table:           f.Table,
			Desc:            f.Desc,
			Excel:           f.Excel,
			Require:         f.Require,
			DefaultValue:    f.DefaultValue,
			ErrorText:       f.ErrorText,
			Clearable:       f.Clearable,
			Sort:            f.Sort,
			PrimaryKey:      f.PrimaryKey,
			DataSource:      ds,
			FieldIndexType:  f.FieldIndexType,
		}
	}

	// 查找主键字段
	var primaryField autocode.AutoCodeField
	for _, f := range fields {
		if f.PrimaryKey {
			primaryField = f
			break
		}
	}
	// 如果没有主键，使用默认的 ID
	if primaryField.FieldName == "" {
		primaryField = autocode.AutoCodeField{
			FieldName: "ID",
			FieldJson: "ID",
			FieldType: "uint",
		}
	}

	// 收集字典类型
	var dictTypes []string
	hasDataSource := false
	for _, f := range fields {
		if f.DictType != "" {
			dictTypes = append(dictTypes, f.DictType)
		}
		if f.DataSource != nil {
			hasDataSource = true
		}
	}

	// 检查特殊字段类型
	hasTimer := false
	hasPic := false
	hasFile := false
	hasRichText := false
	hasArray := false
	needSort := false
	for _, f := range fields {
		switch f.FieldType {
		case "time.Time":
			hasTimer = true
		case "picture":
			hasPic = true
		case "file", "pictures":
			hasFile = true
		case "richtext":
			hasRichText = true
		case "array":
			hasArray = true
		}
		if f.Sort {
			needSort = true
		}
	}

	// 获取模块名
	module := "kra"
	if modFile, err := os.ReadFile("go.mod"); err == nil {
		lines := strings.Split(string(modFile), "\n")
		for _, line := range lines {
			if strings.HasPrefix(line, "module ") {
				module = strings.TrimSpace(strings.TrimPrefix(line, "module "))
				break
			}
		}
	}

	return map[string]interface{}{
		"Package":            config.Package,
		"PackageName":        strings.ToLower(config.Package),
		"PackageT":           strings.Title(config.Package),
		"StructName":         config.StructName,
		"TableName":          config.TableName,
		"Description":        config.Description,
		"BusinessDB":         config.BusinessDB,
		"Abbreviation":       config.Abbreviation,
		"HumpPackageName":    strings.ToLower(string(config.Package[0])) + config.Package[1:],
		"Module":             module,
		"Fields":             fields,
		"PrimaryField":       primaryField,
		"DictTypes":          dictTypes,
		"HasDataSource":      hasDataSource,
		"HasTimer":           hasTimer,
		"HasPic":             hasPic,
		"HasFile":            hasFile,
		"HasRichText":        hasRichText,
		"HasArray":           hasArray,
		"NeedSort":           needSort,
		"GvaModel":           config.Options.GvaModel,
		"AutoMigrate":        config.Options.AutoMigrate,
		"AutoCreateResource": config.Options.AutoCreateResource,
		"OnlyTemplate":       config.Options.OnlyTemplate,
		"IsTree":             config.Options.IsTree,
		"TreeJson":           config.Options.TreeJson,
		"IsAdd":              config.Options.IsAdd,
	}
}

// findTemplateDir 查找模板目录
func findTemplateDir() string {
	// 优先使用命令行指定的模板目录
	if templateDir != "" {
		return templateDir
	}

	// 尝试多个可能的路径
	possiblePaths := []string{
		"resource/package",
		"../resource/package",
		"../../resource/package",
	}

	// 获取可执行文件所在目录
	if execPath, err := os.Executable(); err == nil {
		execDir := filepath.Dir(execPath)
		possiblePaths = append(possiblePaths,
			filepath.Join(execDir, "resource/package"),
			filepath.Join(execDir, "../resource/package"),
		)
	}

	for _, p := range possiblePaths {
		if _, err := os.Stat(p); err == nil {
			return p
		}
	}

	return "resource/package"
}

// renderTemplate 渲染单个模板
func renderTemplate(tplPath string, data map[string]interface{}) (string, error) {
	// 查找模板目录
	baseDir := findTemplateDir()
	resourcePath := filepath.Join(baseDir, tplPath)

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

	// 创建模板
	tmpl, err := template.New(filepath.Base(tplPath)).
		Funcs(autocode.GetTemplateFuncMap()).
		Parse(string(tplContent))
	if err != nil {
		return "", fmt.Errorf("解析模板失败: %w", err)
	}

	// 渲染模板
	var buf bytes.Buffer
	if err := tmpl.Execute(&buf, data); err != nil {
		return "", fmt.Errorf("渲染模板失败: %w", err)
	}

	return buf.String(), nil
}

// executeFullPreview 执行完整预览（显示所有文件内容）
func executeFullPreview(config *AutoCodeConfig) error {
	// 颜色定义
	titleColor := color.New(color.FgCyan, color.Bold)
	fileColor := color.New(color.FgGreen, color.Bold)
	pathColor := color.New(color.FgYellow)
	separatorColor := color.New(color.FgBlue)
	errorColor := color.New(color.FgRed)

	if noColor {
		color.NoColor = true
	}

	// 打印头部信息
	titleColor.Println("╔════════════════════════════════════════════════════════════════╗")
	titleColor.Println("║                    KRA 代码预览 (完整模式)                      ║")
	titleColor.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.Println()

	// 获取模板列表
	templates := getTemplateList(config)

	// 构建模板数据
	data := buildTemplateData(config)

	// 统计信息
	successCount := 0
	failCount := 0
	var failedTemplates []string

	// 渲染并显示每个模板
	for _, tpl := range templates {
		separatorColor.Println("────────────────────────────────────────────────────────────────")
		fileColor.Printf("📄 %s\n", tpl.Name)
		pathColor.Printf("   输出路径: %s\n", tpl.OutputPath)
		fmt.Println()

		content, err := renderTemplate(tpl.Path, data)
		if err != nil {
			errorColor.Printf("   ❌ 渲染失败: %v\n", err)
			failCount++
			failedTemplates = append(failedTemplates, tpl.Name)
			continue
		}

		// 显示代码内容（带语法高亮）
		printCodeWithHighlight(content, tpl.OutputPath)
		successCount++
		fmt.Println()
	}

	// 打印统计信息
	separatorColor.Println("════════════════════════════════════════════════════════════════")
	titleColor.Println("预览统计")
	fmt.Printf("  成功: %d 个文件\n", successCount)
	if failCount > 0 {
		errorColor.Printf("  失败: %d 个文件\n", failCount)
		for _, name := range failedTemplates {
			errorColor.Printf("    - %s\n", name)
		}
	}
	fmt.Println()
	titleColor.Println("⚠️  预览模式 - 未写入任何文件")

	return nil
}

// printCodeWithHighlight 打印代码（带简单语法高亮）
func printCodeWithHighlight(content, filePath string) {
	if noColor {
		fmt.Println(content)
		return
	}

	// 根据文件扩展名确定语言
	ext := strings.ToLower(filepath.Ext(filePath))

	// 简单的语法高亮
	lines := strings.Split(content, "\n")
	for i, line := range lines {
		// 行号
		lineNum := color.New(color.FgHiBlack).Sprintf("%4d │ ", i+1)
		fmt.Print(lineNum)

		// 根据语言类型进行简单高亮
		switch ext {
		case ".go":
			fmt.Println(highlightGo(line))
		case ".tsx", ".ts":
			fmt.Println(highlightTypeScript(line))
		default:
			fmt.Println(line)
		}
	}
}

// highlightGo 简单的 Go 语法高亮
func highlightGo(line string) string {
	if noColor {
		return line
	}

	// 注释
	if strings.HasPrefix(strings.TrimSpace(line), "//") {
		return color.HiBlackString(line)
	}

	// 关键字
	keywords := []string{"package", "import", "func", "type", "struct", "interface",
		"return", "if", "else", "for", "range", "switch", "case", "default",
		"var", "const", "map", "chan", "go", "defer", "select", "break", "continue"}

	result := line
	for _, kw := range keywords {
		// 只替换完整单词
		result = strings.ReplaceAll(result, " "+kw+" ", " "+color.CyanString(kw)+" ")
		result = strings.ReplaceAll(result, "\t"+kw+" ", "\t"+color.CyanString(kw)+" ")
		if strings.HasPrefix(result, kw+" ") {
			result = color.CyanString(kw) + result[len(kw):]
		}
	}

	return result
}

// highlightTypeScript 简单的 TypeScript 语法高亮
func highlightTypeScript(line string) string {
	if noColor {
		return line
	}

	// 注释
	trimmed := strings.TrimSpace(line)
	if strings.HasPrefix(trimmed, "//") || strings.HasPrefix(trimmed, "/*") || strings.HasPrefix(trimmed, "*") {
		return color.HiBlackString(line)
	}

	// 关键字
	keywords := []string{"import", "export", "from", "const", "let", "var", "function",
		"return", "if", "else", "for", "while", "switch", "case", "default",
		"interface", "type", "class", "extends", "implements", "async", "await",
		"try", "catch", "finally", "throw", "new", "this", "super"}

	result := line
	for _, kw := range keywords {
		result = strings.ReplaceAll(result, " "+kw+" ", " "+color.CyanString(kw)+" ")
		result = strings.ReplaceAll(result, "\t"+kw+" ", "\t"+color.CyanString(kw)+" ")
		if strings.HasPrefix(result, kw+" ") {
			result = color.CyanString(kw) + result[len(kw):]
		}
	}

	return result
}
