package compliance

import (
	"bufio"
	"fmt"
	"os"
	"path/filepath"
	"strings"
)

// checkLicense performs static license compliance checks (no regex scanning needed).
func checkLicense(root string) []Finding {
	var findings []Finding

	// L-001: LICENSE file existence
	files := []string{"LICENSE", "LICENSE.md", "LICENSE.txt"}
	found := false
	for _, name := range files {
		if _, err := os.Stat(filepath.Join(root, name)); err == nil {
			found = true
			break
		}
	}
	if !found {
		findings = append(findings, Finding{
			ID: "L-001", Severity: "medium", Module: "license",
			File: "-", Line: 0,
			Summary: "缺少 LICENSE 文件",
		})
	}

	// L-002: check npm/package.json license vs root LICENSE
	rootLicense := detectLicense(root)
	npmLicense := detectNpmLicense(root)
	if rootLicense != "" && npmLicense != "" && !strings.EqualFold(rootLicense, npmLicense) {
		findings = append(findings, Finding{
			ID: "L-002", Severity: "medium", Module: "license",
			File: "npm/package.json", Line: 1,
			Summary: fmt.Sprintf("许可证声明不一致：根 LICENSE 为 %s，npm/package.json 声明 %s", rootLicense, npmLicense),
		})
	}

	// L-004: placeholder check in LICENSE file
	for _, name := range files {
		path := filepath.Join(root, name)
		if f, err := os.Open(path); err == nil {
			sc := bufio.NewScanner(f)
			line := 0
			for sc.Scan() {
				line++
				t := sc.Text()
				if strings.Contains(t, "[year]") || strings.Contains(t, "[Year]") ||
					strings.Contains(t, "[name of copyright holder]") || strings.Contains(t, "[yyyy]") {
					findings = append(findings, Finding{
						ID: "L-004", Severity: "low", Module: "license",
						File: name, Line: line,
						Summary: "LICENSE 中占位符未填写（[Year] / [name of copyright holder]）",
					})
					break
				}
			}
			f.Close()
			break
		}
	}

	return findings
}

func detectLicense(root string) string {
	for _, name := range []string{"LICENSE", "LICENSE.md", "LICENSE.txt"} {
		path := filepath.Join(root, name)
		data, err := os.ReadFile(path)
		if err != nil {
			continue
		}
		text := string(data)
		switch {
		case strings.Contains(text, "Mulan Permissive Software License"):
			return "MulanPSL-2.0"
		case strings.Contains(text, "Apache License") && strings.Contains(text, "Version 2.0"):
			return "Apache-2.0"
		case strings.Contains(text, "MIT License") || strings.Contains(text, "Permission is hereby granted, free of charge"):
			return "MIT"
		case strings.Contains(text, "GNU AFFERO GENERAL PUBLIC LICENSE"):
			return "AGPL-3.0"
		case strings.Contains(text, "GNU GENERAL PUBLIC LICENSE") && strings.Contains(text, "Version 3"):
			return "GPL-3.0"
		case strings.Contains(text, "GNU GENERAL PUBLIC LICENSE") && strings.Contains(text, "Version 2"):
			return "GPL-2.0"
		case strings.Contains(text, "GNU LESSER GENERAL PUBLIC LICENSE"):
			return "LGPL"
		case strings.Contains(text, "BSD") && strings.Count(text, "Redistribution") >= 3:
			return "BSD-3-Clause"
		case strings.Contains(text, "BSD"):
			return "BSD-2-Clause"
		case strings.Contains(text, "Mozilla Public License"):
			return "MPL-2.0"
		default:
			return "unknown"
		}
	}
	return ""
}

func detectNpmLicense(root string) string {
	path := filepath.Join(root, "npm", "package.json")
	data, err := os.ReadFile(path)
	if err != nil {
		return ""
	}
	// simple string search for "license": "xxx"
	for _, line := range strings.Split(string(data), "\n") {
		if strings.Contains(line, "\"license\"") {
			line = strings.TrimSpace(line)
			// "license": "Apache-2.0",
			parts := strings.SplitN(line, ":", 2)
			if len(parts) == 2 {
				v := strings.TrimSpace(parts[1])
				v = strings.Trim(v, "\",")
				return v
			}
		}
	}
	return ""
}

// checkDeps inspects go.mod for copyleft dependencies.
func checkDeps(root string) []Finding {
	var findings []Finding
	path := filepath.Join(root, "go.mod")
	f, err := os.Open(path)
	if err != nil {
		// no go.mod — not a Go project
		return nil
	}
	defer f.Close()

	// GPL/AGPL keywords in module names
	copyleft := []string{"gpl", "agpl", "gnu"}
	sc := bufio.NewScanner(f)
	line := 0
	for sc.Scan() {
		line++
		text := strings.ToLower(sc.Text())
		if !strings.Contains(text, "require") && !strings.Contains(text, "require") {
			continue
		}
		// Check lines after "require" block until blank
	}
	f.Close()

	// re-read go.mod and check require block
	data, err := os.ReadFile(path)
	if err != nil {
		return nil
	}
	lines := strings.Split(string(data), "\n")
	inRequire := false
	for _, l := range lines {
		trimmed := strings.TrimSpace(l)
		if strings.HasPrefix(trimmed, "require") && !strings.Contains(trimmed, "// indirect") {
			inRequire = true
			continue
		}
		if inRequire && trimmed == "" {
			break
		}
		if inRequire && strings.HasPrefix(trimmed, ")") {
			break
		}
		if inRequire {
			lower := strings.ToLower(trimmed)
			for _, kw := range copyleft {
				if strings.Contains(lower, kw) {
					findings = append(findings, Finding{
						ID: "D-003", Severity: "high", Module: "deps",
						File: "go.mod", Line: 0,
						Summary: fmt.Sprintf("Copyleft 依赖风险: %s", trimmed),
					})
					break
				}
			}
		}
	}

	return findings
}
