// Command transpile converts Odoo ES module JS files to odoo.define() format.
// This is a pure Go replacement for tools/transpile_assets.py, eliminating
// the Python dependency entirely.
//
// Usage:
//
//	go run ./cmd/transpile -source ../odoo -output build/js
//	go run ./cmd/transpile -source ../odoo -output build/js -list pkg/server/assets_js.txt
package main

import (
	"bufio"
	"flag"
	"fmt"
	"io"
	"log"
	"os"
	"path/filepath"
	"strings"

	"odoo-go/pkg/server"
)

func main() {
	log.SetFlags(0)

	sourceDir := flag.String("source", "", "Path to Odoo source tree (e.g. ../odoo)")
	outputDir := flag.String("output", "build/js", "Output directory for transpiled JS files")
	listFile := flag.String("list", "pkg/server/assets_js.txt", "Path to the JS asset list file")
	flag.Parse()

	if *sourceDir == "" {
		log.Fatal("error: -source flag is required (path to Odoo source tree)")
	}

	// Resolve paths
	absSource, err := filepath.Abs(*sourceDir)
	if err != nil {
		log.Fatalf("error: invalid source path: %v", err)
	}
	absOutput, err := filepath.Abs(*outputDir)
	if err != nil {
		log.Fatalf("error: invalid output path: %v", err)
	}

	// Read asset list
	jsFiles, err := readAssetList(*listFile)
	if err != nil {
		log.Fatalf("error: reading asset list %s: %v", *listFile, err)
	}

	log.Printf("transpile: %d JS files from %s", len(jsFiles), *listFile)
	log.Printf("transpile: source: %s", absSource)
	log.Printf("transpile: output: %s", absOutput)

	// Addon directories to search (in order of priority)
	addonsDirs := []string{
		filepath.Join(absSource, "addons"),
		filepath.Join(absSource, "odoo", "addons"),
	}

	var transpiled, copied, skipped, errors int

	for _, urlPath := range jsFiles {
		// Find the source file in one of the addons directories
		relPath := strings.TrimPrefix(urlPath, "/")
		sourceFile := findFile(addonsDirs, relPath)
		if sourceFile == "" {
			log.Printf("  SKIP (not found): %s", urlPath)
			skipped++
			continue
		}

		// Read source content
		content, err := os.ReadFile(sourceFile)
		if err != nil {
			log.Printf("  ERROR reading %s: %v", sourceFile, err)
			errors++
			continue
		}

		// Determine output path
		outFile := filepath.Join(absOutput, relPath)

		// Ensure output directory exists
		if err := os.MkdirAll(filepath.Dir(outFile), 0o755); err != nil {
			log.Printf("  ERROR mkdir %s: %v", filepath.Dir(outFile), err)
			errors++
			continue
		}

		src := string(content)

		if server.IsOdooModule(urlPath, src) {
			// Transpile ES module to odoo.define() format
			result := server.TranspileJS(urlPath, src)
			if err := os.WriteFile(outFile, []byte(result), 0o644); err != nil {
				log.Printf("  ERROR writing %s: %v", outFile, err)
				errors++
				continue
			}
			transpiled++
		} else {
			// Not an ES module: copy as-is
			if err := copyFile(sourceFile, outFile); err != nil {
				log.Printf("  ERROR copying %s: %v", urlPath, err)
				errors++
				continue
			}
			copied++
		}
	}

	fmt.Printf("\nDone: %d transpiled, %d copied as-is, %d skipped, %d errors\n",
		transpiled, copied, skipped, errors)
	fmt.Printf("Output: %s\n", absOutput)

	if errors > 0 {
		os.Exit(1)
	}
}

// readAssetList reads a newline-separated list of JS file paths.
func readAssetList(path string) ([]string, error) {
	f, err := os.Open(path)
	if err != nil {
		return nil, err
	}
	defer f.Close()

	var files []string
	scanner := bufio.NewScanner(f)
	for scanner.Scan() {
		line := strings.TrimSpace(scanner.Text())
		if line != "" && !strings.HasPrefix(line, "#") {
			files = append(files, line)
		}
	}
	return files, scanner.Err()
}

// findFile searches for a relative path in the given directories.
func findFile(dirs []string, relPath string) string {
	for _, dir := range dirs {
		candidate := filepath.Join(dir, relPath)
		if info, err := os.Stat(candidate); err == nil && !info.IsDir() {
			return candidate
		}
	}
	return ""
}

// copyFile copies a file from src to dst.
func copyFile(src, dst string) error {
	in, err := os.Open(src)
	if err != nil {
		return err
	}
	defer in.Close()

	out, err := os.Create(dst)
	if err != nil {
		return err
	}
	defer out.Close()

	_, err = io.Copy(out, in)
	return err
}
