package main

import (
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"sort"
	"strings"

	"github.com/hhatto/gocloc"
)

func main() {
	out, err := exec.Command("git", "ls-files").Output()
	if err != nil {
		fmt.Fprintf(os.Stderr, "git ls-files: %v\n", err)
		os.Exit(1)
	}

	allFiles := strings.Split(strings.TrimSpace(string(out)), "\n")

	var files []string
	for _, f := range allFiles {
		f = strings.TrimSpace(f)
		if f == "" {
			continue
		}
		norm := filepath.ToSlash(f)
		if strings.HasPrefix(norm, "vendor/") || strings.Contains(norm, "/vendor/") {
			continue
		}
		files = append(files, f)
	}

	opts := gocloc.NewClocOptions()
	langs := gocloc.NewDefinedLanguages()

	// gocloc maps "TypeScript" instead of "ts" in its Exts table
	extAliases := map[string]string{
		"ts": "TypeScript",
	}

	total := gocloc.NewLanguage("TOTAL", []string{}, [][]string{{"", ""}})
	languages := make(map[string]*gocloc.Language)
	clocFiles := make(map[string]*gocloc.ClocFile)

	for _, file := range files {
		file = strings.TrimSpace(file)
		if file == "" {
			continue
		}

		ext := filepath.Ext(file)
		if ext == "" {
			continue
		}
		ext = ext[1:]

		langName, ok := gocloc.Exts[ext]
		if !ok {
			langName, ok = extAliases[ext]
			if !ok {
				continue
			}
		}

		def := langs.Langs[langName]
		if def == nil {
			continue
		}

		cf := gocloc.AnalyzeFile(file, def, opts)
		cf.Lang = langName
		clocFiles[file] = cf

		if _, exists := languages[langName]; !exists {
			languages[langName] = gocloc.NewLanguage(def.Name, []string{}, [][]string{{"", ""}})
		}
		lang := languages[langName]
		lang.Files = append(lang.Files, file)
		lang.Code += cf.Code
		lang.Comments += cf.Comments
		lang.Blanks += cf.Blanks

		total.Code += cf.Code
		total.Comments += cf.Comments
		total.Blanks += cf.Blanks
	}

	type row struct {
		Name     string
		Files    int
		Code     int32
		Comments int32
		Blanks   int32
	}

	var rows []row
	for name, lang := range languages {
		rows = append(rows, row{
			Name:     name,
			Files:    len(lang.Files),
			Code:     lang.Code,
			Comments: lang.Comments,
			Blanks:   lang.Blanks,
		})
	}
	sort.Slice(rows, func(i, j int) bool {
		return rows[i].Code > rows[j].Code
	})

	divider := "-------------------------------------------------------------------------------"
	fmt.Println(divider)
	fmt.Printf("%-25s %10s %10s %10s %10s\n", "Language", "Files", "Code", "Comment", "Blank")
	fmt.Println(divider)
	for _, r := range rows {
		fmt.Printf("%-25s %10d %10d %10d %10d\n", r.Name, r.Files, r.Code, r.Comments, r.Blanks)
	}
	fmt.Println(divider)
	fmt.Printf("%-25s %10d %10d %10d %10d\n",
		"Total",
		len(clocFiles),
		total.Code,
		total.Comments,
		total.Blanks,
	)
	fmt.Println(divider)
}
